<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Get Info: #gamedev</title>
    <description>Posts tagged “gamedev” — Blog of independent game and app developer Matt Sephton. Featuring vintage Macintosh, game development, digital artwork, Japanese esoterica, video game reviews, hacks and tips, and much more.</description>
    <link>https://blog.gingerbeardman.com/tag/gamedev/</link>
    <atom:link href="https://blog.gingerbeardman.com/tag/gamedev/index.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 03 Jul 2026 20:16:48 +0000</pubDate>
    <lastBuildDate>Fri, 03 Jul 2026 20:16:48 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>

    
      
        <item>
          <title>New (Old) 3D Golf: porting PC-9801 &amp; Virtual Boy to Mega Drive</title>
          <description>&lt;p&gt;The Japanese Mega Drive ports of T&amp;amp;E SOFT’s &lt;a href=&quot;/2024/11/09/new-3d-golf-simulation-video-game-series/&quot;&gt;New 3D Golf Simulation&lt;/a&gt; series are my favourite golf games, and recently I’ve been living inside their ROMs.&lt;/p&gt;

&lt;p&gt;As with all the craziest ideas, it began with a “I wonder if I could”… In the early hours of one April morning I managed to pull a single course out of the game—its terrain and flyby data—and reimplement it in a viewer of my own, written in Three.js. Over the following week or so of continued reverse engineering, that viewer quietly grew into something resembling a 3D golf game running in the browser. Finding the data had some big clues: we know that there are 18 holes, the distances of each hole and their sequence order, and I’d read the courses were made of ~256 points, so adding all these heuristics together meant it was much easier to find the data than finding a needle in a haystack.&lt;/p&gt;

&lt;p&gt;Understanding the data that well meant I could go the other way, too—&lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mkgnbdzljc2o&quot;&gt;back into the original Mega Drive games&lt;/a&gt; themselves. First I added a terrain modifier. To test it I &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mkkxeaebm22c&quot;&gt;flattened the entire course like a pancake&lt;/a&gt; to confirm my understanding was correct, and then cranked it up to 11 into a sort of &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mkpwexii4c2t&quot;&gt;“Hyperactive Terrain Mode”&lt;/a&gt; that warps the fairways into something wild. Both worked well.&lt;/p&gt;

&lt;p&gt;An early attempt changed its mind on every run; turned out I was seeding it from an uninitialised memory location. 🤦 With no debugger console to hand, I’d been hunting bugs like this the crude way—scribbling values into the cartridge’s SRAM (its battery-backed save memory) and reading them back out, a poor man’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf&lt;/code&gt;. So it wasn’t exactly straightforward.&lt;/p&gt;

&lt;p&gt;Once that was sorted, I gave the 32-year-old game some &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mkt6k57nlc2e&quot;&gt;brand new, custom user interface&lt;/a&gt; to match.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 4/3;&quot; videoid=&quot;HHbEVRtbw7Q&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;Next I wondered if the course data was the same across all of the four Mega Drive games, could it be the same across the games on other platforms? The answer is &lt;strong&gt;yes&lt;/strong&gt;: &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3ml2k552qis2f&quot;&gt;the same course data format&lt;/a&gt; turns out to be used right across the series, from the original PC-9801 games (and almost certainly X68000 and FM Towns) through to the Mega Drive and even the Virtual Boy. If my (little-endian) maths is correct that’s a total of 7 unique courses, all sharing one format. There’s some reformatting that needs to be done, but the data structure is the same. And since I could already read the courses, I could write them too—patching the games to pick a course at random, or to load one that was never available on the Mega Drive in the first place. PC-9801 to Mega Drive required sorting the polygons to match how they were expected to be stored.&lt;/p&gt;

&lt;p&gt;But I guess T&amp;amp;E SOFT used the same POLYSYS-CAD software to design all the courses over several years? I love how such a tool could have that sort of longevity.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/new-old-golf-polysyscad.jpg&quot; alt=&quot;IMG&quot; title=&quot;ポリシスCAD (POLYSYS-CAD) PC software used to design hole topology mesh of only ~256 points&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;That last part is the really fun bit. (Can this even &lt;em&gt;be&lt;/em&gt; more fun?)&lt;/p&gt;

&lt;p&gt;Here are three courses running on the Mega Drive for the first time:&lt;/p&gt;

&lt;h2 id=&quot;te-selection&quot;&gt;T&amp;amp;E Selection&lt;/h2&gt;

&lt;p&gt;Extracted from the &lt;a href=&quot;https://www.mobygames.com/game/102547/new-3d-golf-simulation-te-selection/&quot;&gt;NEC PC-9801 add-on course disk&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This course is somewhat unique as it has messages spelled using coloured topology:&lt;br /&gt;
the 1st has “GO!” by the tee position; the 18th has “T&amp;amp;E” just beyond the final green&lt;/p&gt;
&lt;/blockquote&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 4/3;&quot; videoid=&quot;duXwfq-F-CA&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;eight-lakes-gc&quot;&gt;Eight Lakes G.C.&lt;/h2&gt;

&lt;p&gt;Also extracted from &lt;a href=&quot;https://www.mobygames.com/game/71396/new-3d-golf-simulation-eight-lakes-gc/&quot;&gt;NEC PC-9801 add-on course disk&lt;/a&gt;:&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 4/3;&quot; videoid=&quot;J0PliXErDNU&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;blockquote&gt;
  &lt;p&gt;A fact perhaps only I care about: &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mmmt2mkrzc2z&quot;&gt;during development, prior to Feb 1990, it was &lt;em&gt;Seven Lakes G.C.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/new-old-golf-seven-lakes.webp&quot; alt=&quot;Seven Lakes G.C.&quot; title=&quot;Seven Lakes G.C., as seen in Comptiq Vol. 63 &amp;amp; Oh! PC Issue 117&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;papillon-cc&quot;&gt;Papillon C.C.&lt;/h2&gt;

&lt;p&gt;Extracted from the Nintendo Virtual Boy game &lt;a href=&quot;https://www.mobygames.com/game/15306/golf/&quot;&gt;T&amp;amp;E Virtual Golf&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s called Papillon—the French word for butterfly—because the course holes were laid out in the shape of a butterfly. Which was surely a nod to the shape of the Virtual Boy controller.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 4/3;&quot; videoid=&quot;8Hpnm4w4EDU&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;That last one needed a little extra work. T&amp;amp;E Golf on Virtual Boy doesn’t have a hole flyby, so I had to generate the camera path myself: a bezier curve from tee to pin, nudged towards the centre point of the visible course as it appears on the mini-map. The flyby path in this video was about half way to my final solution.&lt;/p&gt;

&lt;p&gt;Playing these courses on Mega Drive is truly special and the effort was very much worthwhile. 🥰&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-few-things-i-learned-along-the-way&quot;&gt;A few things I learned along the way&lt;/h2&gt;

&lt;p&gt;Living inside the disassembly for weeks, I kept tripping over the little decisions T&amp;amp;E SOFT made all those years ago. Some are clever, some are quietly bonkers, and all of them made me grin:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The hole is three times too big.&lt;/strong&gt; The cup grabs any ball within ~6.7 inches—triple a real hole’s radius—so balls drop from further out than they look. A fudge for the 320×224 screen, where ball and cup were both sub-pixel.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The polygons pre-sort themselves.&lt;/strong&gt; No depth buffer on the Mega Drive, so the draw order is baked into the course data, back-to-front (the painter’s algorithm). The giveaway: it doesn’t match the original PC-9801 CAD order.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Backspin can reverse a putt.&lt;/strong&gt; Spin isn’t cosmetic: it’s fed back into the roll and can make the ball check up and trickle backwards. Real ballistic physics in a 1993 cartridge. Love it!&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Water isn’t a hazard—just very sticky.&lt;/strong&gt; There’s no “in the water” state; water polygons carry friction so high it kills the ball in one frame. The penalty falls out of the ordinary maths.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wind is a real force, not an aim fudge.&lt;/strong&gt; It becomes a horizontal acceleration applied every frame of flight, exactly like gravity.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Augusta’s wind never actually changes.&lt;/strong&gt; The direction is never written—only strength varies. The arrow only seems to swing because it’s drawn relative to the camera.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bunkers plug, cart paths kick.&lt;/strong&gt; Every surface has its own bounce coefficient. The fairway hands back a healthy ~40% of the ball’s speed; a bunker returns only ~10%, so the ball plugs where it lands; a cart path or rock fires it back at ~75% for that horrible hard skip.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Your lie quietly rolls the dice.&lt;/strong&gt; On every stroke the game picks a random number from a per-(lie, club) range and folds it into your swing power. A clean fairway lie uses a narrow range; a bad lie widens it—so the rough genuinely makes your shots less predictable. The ranges live in a 17×17 table, one entry per lie-and-club combination.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;four-volumes-one-evolving-engine&quot;&gt;Four volumes, one evolving engine&lt;/h2&gt;

&lt;p&gt;It’s tempting to treat the four Mega Drive games as a single engine with interchangeable courses. They’re not, and the very first line of the cross-volume notes I kept is a warning to myself: ⚠️ &lt;em&gt;never assume all four ROMs share code or data layouts.&lt;/em&gt; T&amp;amp;E SOFT kept tinkering release to release, and you only catch it by dumping the same region in all four disassemblies and diffing.&lt;/p&gt;

&lt;p&gt;The ROM headers number them &lt;em&gt;New 3D Golf Simulation&lt;/em&gt; Vol.1–4, and each header also carries a build date stamped in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YYYY.MMM&lt;/code&gt; form. Here’s the curiosity: the volume numbers track the &lt;strong&gt;build&lt;/strong&gt; dates, not the retail release dates. Vol.2 &lt;em&gt;Devil’s Course&lt;/em&gt; was finished a month before Vol.3 &lt;em&gt;Augusta&lt;/em&gt;—but reached the shops a month after it:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Vol&lt;/th&gt;
      &lt;th&gt;Title&lt;/th&gt;
      &lt;th&gt;Japanese&lt;/th&gt;
      &lt;th&gt;ROM build&lt;/th&gt;
      &lt;th&gt;Retail release&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Pebble Beach no Hatou&lt;/td&gt;
      &lt;td&gt;ペブルビーチの波濤&lt;/td&gt;
      &lt;td&gt;1993-07&lt;/td&gt;
      &lt;td&gt;1993-10-29&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;Devil’s Course&lt;/td&gt;
      &lt;td&gt;デビルズコース&lt;/td&gt;
      &lt;td&gt;1993-08&lt;/td&gt;
      &lt;td&gt;1994-01-28&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;Harukanaru Augusta&lt;/td&gt;
      &lt;td&gt;遙かなるオーガスタ&lt;/td&gt;
      &lt;td&gt;1993-09&lt;/td&gt;
      &lt;td&gt;1993-12-17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;Waialae no Kiseki&lt;/td&gt;
      &lt;td&gt;ワイアラエの奇蹟&lt;/td&gt;
      &lt;td&gt;1993-09&lt;/td&gt;
      &lt;td&gt;1994-02-25&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A couple of header quirks fell out of this. Pebble’s stamp reads &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1993.JLY&lt;/code&gt;—Sega’s own oddball abbreviation for July. And while three of the carts credit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SEGA&lt;/code&gt;, &lt;em&gt;Augusta&lt;/em&gt; credits T&amp;amp;E Soft’s Sega licensee code &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T-114&lt;/code&gt; instead—a clue that it alone was self-published by T&amp;amp;E SOFT rather than by Sega. The boxes agree: Augusta’s isn’t Sega-branded either.&lt;/p&gt;

&lt;p&gt;Two places they genuinely diverge, each confirmed by dumping the same region in all four:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Colour isn’t a plain palette lookup—and the recipe is per-game.&lt;/strong&gt; A surface byte runs through a little chain of lookup tables before it becomes a pen colour, and those tables aren’t shared: Pebble grades several surfaces differently and even reorders two entries, while Devil’s Course carries its own darker, redder palette. Waialae, charmingly, reuses a single palette three times where its siblings have three distinct ones.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A decoder bug only Pebble could trigger.&lt;/strong&gt; In the polygon stream, vertex indices are single bytes, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xFF&lt;/code&gt; acting as an escape prefix—the byte after it encodes a higher index (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xE0 + xx&lt;/code&gt;), so a hole can point past the ~254 vertices a lone byte can name. My extractor mishandled that escaped range, but only Pebble’s holes are dense enough to actually &lt;em&gt;use&lt;/em&gt; it—so the bug sailed through the other three games and only fell over when I reached Pebble. Same encoding in every cart; one course’s data was all it took to expose the flaw in my reader.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s also the US release, &lt;em&gt;Pebble Beach Golf Links&lt;/em&gt; (header stamped 1993-11, likely on shelves 1994-04): the same course data on a larger ROM, with English strings present where the Japanese Vol.1 zeroed them. That parallel made a useful “Rosetta Stone” for decoding menus and text.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;inside-waialae&quot;&gt;Inside Waialae&lt;/h2&gt;

&lt;p&gt;Waialae was my primary reference—1,572,864 bytes, header &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEW 3D GOLF SIMULATION Vol.4 Waialae C.C.&lt;/code&gt;, serial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GM G-5529&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each hole is reached through four ROM pointers, one per data block, and they’re wildly different sizes. Block 0 is the vertex list—244 XYZ points, the ~256-point mesh, about 1.5 KB. Block 1 is the bulk of it: sixteen view-order streams (one draw order per camera angle) that bake in the back-to-front sorting—around 5.5 KB, bigger than the geometry it orders. Block 2 holds the mesh and sprites themselves (230 polygons plus 54 sprites), ~1.8 KB. Block 3 is just the flyby keyframes, a slim ~0.7 KB. For Waialae’s first hole that comes to about 9.2 KB, split like this:&lt;/p&gt;

&lt;svg viewBox=&quot;0 0 740 94&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-labelledby=&quot;holeDesc&quot; style=&quot;display:block;margin:0 auto;width:100%;max-width:740px;height:auto;font-family:-apple-system,BlinkMacSystemFont,&apos;Segoe UI&apos;,Helvetica,Arial,sans-serif&quot;&gt;
  &lt;desc id=&quot;holeDesc&quot;&gt;One bar representing a hole&apos;s data for Waialae hole 1, split into four segments by size: Block 0 vertex list 1,466 bytes; Block 1 view-order streams 5,490 bytes; Block 2 mesh and sprites 1,758 bytes; Block 3 flyby keyframes 666 bytes.&lt;/desc&gt;
  &lt;rect x=&quot;12&quot; y=&quot;8&quot; width=&quot;112&quot; height=&quot;78&quot; fill=&quot;#c5e0b4&quot; stroke=&quot;#2f5e22&quot; /&gt;
  &lt;rect x=&quot;124&quot; y=&quot;8&quot; width=&quot;419&quot; height=&quot;78&quot; fill=&quot;#538135&quot; stroke=&quot;#2f5e22&quot; /&gt;
  &lt;rect x=&quot;543&quot; y=&quot;8&quot; width=&quot;134&quot; height=&quot;78&quot; fill=&quot;#70ad47&quot; stroke=&quot;#2f5e22&quot; /&gt;
  &lt;rect x=&quot;677&quot; y=&quot;8&quot; width=&quot;51&quot; height=&quot;78&quot; fill=&quot;#a9d18e&quot; stroke=&quot;#2f5e22&quot; /&gt;
  &lt;text x=&quot;22&quot; y=&quot;28&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#1f3b14&quot;&gt;Block 0&lt;/text&gt;
  &lt;text x=&quot;22&quot; y=&quot;46&quot; font-size=&quot;11&quot; fill=&quot;#33521f&quot;&gt;Vertex list&lt;/text&gt;
  &lt;text x=&quot;22&quot; y=&quot;64&quot; font-size=&quot;11&quot; fill=&quot;#33521f&quot;&gt;1,466 B&lt;/text&gt;
  &lt;text x=&quot;134&quot; y=&quot;28&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#ffffff&quot;&gt;Block 1 · View-order streams&lt;/text&gt;
  &lt;text x=&quot;134&quot; y=&quot;46&quot; font-size=&quot;11&quot; fill=&quot;#e7f2dd&quot;&gt;one draw order per camera angle (×16)&lt;/text&gt;
  &lt;text x=&quot;134&quot; y=&quot;64&quot; font-size=&quot;11&quot; fill=&quot;#e7f2dd&quot;&gt;5,490 B&lt;/text&gt;
  &lt;text x=&quot;553&quot; y=&quot;28&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#14300a&quot;&gt;Block 2&lt;/text&gt;
  &lt;text x=&quot;553&quot; y=&quot;46&quot; font-size=&quot;11&quot; fill=&quot;#14300a&quot;&gt;Mesh + sprites&lt;/text&gt;
  &lt;text x=&quot;553&quot; y=&quot;64&quot; font-size=&quot;11&quot; fill=&quot;#14300a&quot;&gt;1,758 B&lt;/text&gt;
  &lt;text x=&quot;683&quot; y=&quot;28&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#1f3b14&quot;&gt;Block 3&lt;/text&gt;
  &lt;text x=&quot;683&quot; y=&quot;46&quot; font-size=&quot;11&quot; fill=&quot;#1f3b14&quot;&gt;Flyby&lt;/text&gt;
  &lt;text x=&quot;683&quot; y=&quot;64&quot; font-size=&quot;11&quot; fill=&quot;#1f3b14&quot;&gt;666 B&lt;/text&gt;
&lt;/svg&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;A couple more structural quirks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;A spatial grid, decades early.&lt;/strong&gt; Immediately after the vertex pool sits a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count&lt;/code&gt; followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count × 16&lt;/code&gt; word offsets into the face section—a two-level spatial grid (cell → faces) so the engine can look up the relevant polygons from the ball’s (x, z) without walking the whole hole.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Why the SRAM debugging hurt.&lt;/strong&gt; Waialae’s battery-backed save RAM is odd-lane only, from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$200001&lt;/code&gt;. Byte writes have to land on odd Mega Drive addresses; even-address writes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$200000&lt;/code&gt; simply disappear. That’s the real reason scribbling values into SRAM as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf&lt;/code&gt; substitute was so finicky—half my early writes were going into the void. (BlastEm helpfully flushes SRAM to disk on quit, so I could read it back from the host.)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;variable-zoom&quot;&gt;Variable zoom&lt;/h2&gt;

&lt;p&gt;The shared course format is what let me move holes between platforms, but each machine scales the world differently. The proven case: Waialae hole 1 from the PC-9801 drops into the Mega Drive after a fixed &lt;strong&gt;1.6× rescale on X and Z&lt;/strong&gt; (Y untouched), plus a &lt;strong&gt;little-endian → big-endian flip&lt;/strong&gt; on the flyby path records.&lt;/p&gt;

&lt;p&gt;Lining those transplanted polygons up against the stock Mega Drive ones is also what &lt;em&gt;proved&lt;/em&gt; the rendering trick I mentioned earlier: the Mega Drive packs faces in descending max-Z order—back to front, the painter’s algorithm—and the original PC-9801 face id survives the journey as the Mega Drive’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attr1&lt;/code&gt; byte.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;two-deeper-cuts&quot;&gt;Two deeper cuts&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The flyby camera, decoded by statistics.&lt;/strong&gt; Each flyby keyframe carries two mystery bytes. With no documentation, I histogrammed 4,723 of them across every hole and the shape gave it away: one byte is an 8-bit angle (256 units = 360°) for yaw, the other a signed pitch clamped to about ±40, positive meaning the camera looks down. Educated guessing, with visuals.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The Virtual Boy world is built at a different scale.&lt;/strong&gt; The Virtual Boy stores its courses at 32 raw units per yard, where the Mega Drive works in 17—so Papillon has to be shrunk by exactly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;17/32&lt;/code&gt; (0.53) to sit correctly on the Mega Drive, otherwise every club hits too short for the hole. (My first attempt used the wrong unit and reported hole 1 as 321 yards instead of its true 360.) It’s the same idea as the 1.6× I needed coming the other way from the PC-9801—one shared format, but every machine measures its yards differently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing ran on rizin and vasmm68k with BlastEm for execution—though frame-time profiling had to move to Genesis Plus GX, because BlastEm freezes the VDP’s HV counter during the long rendering routines I was trying to measure.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-the-old-magazines-turned-up&quot;&gt;What the old magazines turned up&lt;/h2&gt;

&lt;p&gt;Reverse engineering only tells you &lt;em&gt;what&lt;/em&gt; the games do; for the &lt;em&gt;why&lt;/em&gt;, I went digging through a stack of Japanese computer magazines from the era, OCRing the scans to pull out the text. A 1989 developer interview about &lt;em&gt;Harukanaru Augusta&lt;/em&gt; (遙かなるオーガスタ)—the PC-9801 original that kicked off the series—turned out to be a goldmine:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The 3D engine came first.&lt;/strong&gt; T&amp;amp;E’s POLYSYS pre-dated the golf games by a couple of years, already appearing—only in the 3D intro logos, as far as I can tell—in &lt;em&gt;DAIVA STORY 7: Light of Kali Yuga&lt;/em&gt; and &lt;em&gt;Psy-O-Blade&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Trees were nearly real 3D.&lt;/strong&gt; They tried modelling trees as polygons, leaves and all—but one tree took as long to draw as a whole screen. So scaled sprites were used instead.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The first game had no hills.&lt;/strong&gt; T&amp;amp;E’s &lt;em&gt;3-D Golf Simulation&lt;/em&gt;, written in BASIC six years earlier, had no terrain undulation at all—and on the Sharp X1, 18 holes took &lt;em&gt;half a day&lt;/em&gt; to play through.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;POLYSYS was meant to be general-purpose:&lt;/strong&gt; swap the data and it renders anything. T&amp;amp;E planned an RPG and a shooter on it and intended to license it to other software houses.&lt;/li&gt;
  &lt;li&gt;One programmer, mostly: &lt;strong&gt;Eiji Kato&lt;/strong&gt; (加藤英治).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the &lt;em&gt;Augusta&lt;/em&gt; course itself came with a wonderful backstory:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;They licensed the real thing.&lt;/strong&gt; An official contract with Augusta National, working from the club’s blueprints. Staff visited, didn’t play, but “rubbed their cheeks on the grass.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Augusta sent back ~60 corrections:&lt;/strong&gt; eg. pine trees too short and too spread out, flowers too pink, bunker sand the wrong colour.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No do-overs, by design.&lt;/strong&gt; You could save mid-round, but loading erased the save data—so no replaying holes to pad your score.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Best of all:&lt;/strong&gt; the dev build’s four caddies were all women. Augusta’s are all men, so the final game swapped them. The ladies returned in the expansion courses and Mega Drive games.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The T&amp;amp;E Selection caddies are real people:&lt;/strong&gt; four women who worked at &lt;strong&gt;Brother Industries&lt;/strong&gt;—whose &lt;strong&gt;TAKERU&lt;/strong&gt; software vending machines sold these add-on course disks.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-next&quot;&gt;What Next?&lt;/h2&gt;

&lt;p&gt;There’s an extra bit of hacking I’m working on but am unsure if it will lead to anything, but if it does it will need a post all of its own. Hold your thumbs. Fingers crossed. 🤞&lt;/p&gt;

&lt;p&gt;It would be possible to release a small script which given both original games would do the extraction and patching, but for now I don’t feel comfortable doing that. I still need to figure out the correct tree mapping for each game, decide which of the four Mega Drive games is most suited to each of the three new courses, add new title screens and a few more bits of detail work.&lt;/p&gt;

&lt;p&gt;I’d love to &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3mnhbioqr4s2f&quot;&gt;see these ported courses released officially&lt;/a&gt; some day—the series IP is now owned and managed by D4 Enterprise—so if you know anybody there please hook us up! If you are an employee of D4 Enterprise then please check my request to license the IP. 🙏&lt;/p&gt;

&lt;p&gt;There are more period games in the series that I’d like to take a look at to see if they use the same data format, or modify it in any specific way. SNES and 3DO seem to be the most interesting. 🧐&lt;/p&gt;

&lt;p&gt;But for now it’s just me, a pile of disassembly files, rizin and vasmm68k, the BlastEm emulator, and a soft spot for blue skies and FM synth — still trying to get the ball in the hole. ⛳️🏌️‍♂️&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 19 Jun 2026 16:26:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2026/06/19/new-old-3d-golf-porting-pc-9801-and-virtual-boy-to-mega-drive/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2026/06/19/new-old-3d-golf-porting-pc-9801-and-virtual-boy-to-mega-drive/</guid>
        </item>
      
    
      
        <item>
          <title>Serenity: zen gliding to the sound of procedurally generated music</title>
          <description>&lt;p&gt;Today I’m releasing a demo of my new game: Serenity.&lt;/p&gt;

&lt;p&gt;It’s available for both Mac and Windows, and the final game will also support Linux.&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://store.steampowered.com/app/4309910/Serenity_Demo/?beta=1&quot;&gt;store.steampowered.com/app/4309910/Serenity_Demo/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/serenity-gameplay.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-universe-provides&quot;&gt;The Universe Provides&lt;/h2&gt;

&lt;p&gt;The story of this game is a strange one, so perhaps worth telling. I was about to add online play to a different game project and wanted a smaller game to test &lt;a href=&quot;https://joinplayroom.com&quot;&gt;PlayroomKit&lt;/a&gt;, the solution I had chosen. As Thanksgiving 2025 approached I wondered what personal project I could do over the break that might be a quick way to prove the online concept. I’d been working in 3D using Three.js for a while, so my mind wandered to all of my favourite 3D game experiences. I wondered how difficult it would be to create something along the lines of an old favourite of mine: Tranquility.&lt;/p&gt;

&lt;p&gt;Later that day I was emailing the musicians I was working with, &lt;a href=&quot;https://linktr.ee/novasphere2000&quot;&gt;Nova Sphere&lt;/a&gt;, and when I returned to my inbox—filtered with the search term “sphere”—there was an email I had been waiting on for something like 20 years: it was from Bill Romanowski, the creator of Tranquility. This was a sign that the Universe really does provide, so I set to work.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-demo&quot;&gt;The Demo&lt;/h2&gt;

&lt;p&gt;From that point on I put all my spare time into the game and by Boxing Day I had finished what I would consider the MVP, vertical slice, or whatever you want to call it. That’s essentially what this demo is. You can &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3maw3yoo5q22d&quot;&gt;read a sort of director’s commentary of the game development and my philosophy&lt;/a&gt; in a thread on Bluesky. I signed up to Steam, paid my fee, and submitted to Steam Next Fest: February 2026 Edition. I thought it would be fun to release the demo ahead of that event because I’m travelling to Japan for the Tokyo Design Forum between now and then.&lt;/p&gt;

&lt;p&gt;This demo is a snapshot from early January and the game has been refined and improved in countless ways since. So, please go easy on the demo and look forward to the final version. Visually, it’s obviously inspired by Tranquility but given that I was creating it with little more than a memory of how that game felt to play back in the day, it contains a lot more. Depending on your point of view, it might strike you as a &lt;em&gt;3D&lt;/em&gt; Electroplankton, Jumping Flash! crossed with Zarch, Tiny Wings in space, Proteus without the trees, or Journey set in the Matrix. My list of influences is wide and varied—not just for the game but also for the procedurally generated levels and music. And of course there is a lot of what I like to think only I can bring to the table. I hope you enjoy it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-inspirations&quot;&gt;The Inspirations&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/939/continuum/&quot;&gt;Alpha Waves&lt;/a&gt; (1990)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/20757/electroplankton/&quot;&gt;Electroplankton&lt;/a&gt; (2005)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/39287/flower/&quot;&gt;Flower&lt;/a&gt; (2009)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/55167/journey/&quot;&gt;Journey&lt;/a&gt; (2012)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/5050/jumping-flash/&quot;&gt;Jumping Flash!&lt;/a&gt; (1995)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/109325/panekit/&quot;&gt;Panekit&lt;/a&gt; (1999)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/59643/proteus/&quot;&gt;Proteus&lt;/a&gt; (2013)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/93633/tiny-wings/&quot;&gt;Tiny Wings&lt;/a&gt; (2011)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/48430/tranquility/&quot;&gt;Tranquility&lt;/a&gt; (1992)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/19494/virus/&quot;&gt;Zarch&lt;/a&gt; (1987)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-future&quot;&gt;The Future&lt;/h2&gt;

&lt;p&gt;I’m still working hard on the final game, which will release later in 2026. I’m currently courting publishers, so if you like what you see please get in touch. I’d love to get this onto consoles.&lt;/p&gt;

&lt;p&gt;I’ll be sure to write more about the game as it gets closer to the finish line, but the current development version has better onboarding, improved music, even higher performance (the demo is 60fps, but the final version is more adaptive). There’s a lot to talk about, but if you’re hungry for more, &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3maw3yoo5q22d&quot;&gt;check out my director’s commentary thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the short term I’ll be showing Serenity at &lt;a href=&quot;https://www.tokyoindies.com/en/&quot;&gt;Tokyo Indies&lt;/a&gt; on 18th February. I’d love to see you there.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-trailer&quot;&gt;The Trailer&lt;/h2&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 71/51;&quot; videoid=&quot;6kuETNxSWVM&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 12 Feb 2026 17:53:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2026/02/12/serenity-demo/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2026/02/12/serenity-demo/</guid>
        </item>
      
    
      
        <item>
          <title>WebGL CRT Shader</title>
          <description>&lt;p&gt;I’m releasing my WebGL CRT Shader as open source.&lt;/p&gt;

&lt;p&gt;It creates a CRT/vintage TV effect so could be used in games, emulators, apps, demos, visuals, etc. It’s not a simulator just something that gives the same general old school vibe.&lt;/p&gt;

&lt;p&gt;As a WebGL shader, it runs on the device’s hardware GPU in the browser and renders to a &amp;lt;canvas&amp;gt; (or offscreen canvas). I currently use it with Three.js, and the demo below uses just a 2D canvas.&lt;/p&gt;

&lt;p&gt;It’s optimised to run well on low power devices as far back as iPhone XS, though I’m certain it can be optimised even further. &lt;a href=&quot;https://github.com/gingerbeardman/webgl-crt-shader/pulls&quot;&gt;PRs welcome&lt;/a&gt;! The easiest personal optimisation you might make would be removing processing of unused parameters.&lt;/p&gt;

&lt;p&gt;Is it scientifically correct? &lt;em&gt;Hell no.&lt;/em&gt; Does it look good? &lt;em&gt;Yes.&lt;/em&gt; Does it give you the feels? &lt;em&gt;Absolutely.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/gingerbeardman/webgl-crt-shader/&quot;&gt;github.com/gingerbeardman/webgl-crt-shader/&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;

&lt;p&gt;It began as a &lt;a href=&quot;https://bsky.app/profile/gingerbeardman.com/post/3lk2arnt4rc2o&quot;&gt;shader for Love2D&lt;/a&gt; at the beginning of 2025 (&lt;a href=&quot;https://gist.github.com/gingerbeardman/7392ee84fdb2e405d7437b5b12e4c12d&quot;&gt;here’s a gist of that one&lt;/a&gt;) and by the end of 2025 I had ported it to GLSL for a personal work-in-progress web game.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;live-demo&quot;&gt;Live Demo&lt;/h2&gt;

&lt;p&gt;Reach for the sliders!&lt;/p&gt;

&lt;p&gt;(You can scroll the demo horizontally on mobile)&lt;/p&gt;

&lt;div class=&quot;table-wrapper&quot;&gt;

  &lt;iframe src=&quot;https://gingerbeardman.github.io/webgl-crt-shader/&quot; width=&quot;740&quot; height=&quot;740&quot;&gt;
![screenshot](https://cdn.gingerbeardman.com/images/posts/glsl-web-crt-shader.png)
&lt;/iframe&gt;

&lt;/div&gt;

&lt;p&gt;^ Screenshot is Pico-8 classic &lt;a href=&quot;https://www.lexaloffle.com/bbs/?tid=3547&quot;&gt;Worm Nom Nom&lt;/a&gt; by Tic Tac Toad (kometbomb + iLKke) 🌸🍏🎩🐛💩&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 04 Jan 2026 17:44:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2026/01/04/webgl-crt-shader/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2026/01/04/webgl-crt-shader/</guid>
        </item>
      
    
      
        <item>
          <title>Post-Playdate: One Year Later</title>
          <description>&lt;p&gt;It’s been a year since October 2024, when I released &lt;a href=&quot;/2024/10/08/bender-2-bend-harder-for-playdate/&quot;&gt;my last game on the Playdate Catalog&lt;/a&gt;. Over the course of that month, I became increasingly concerned about an undercurrent of threatening and antisocial behaviour from one particular developer in the community—my frequent reports of which went unanswered. Eventually—exactly a year ago today—that tension surfaced as a campaign of targeted harassment. I was assured something would be done about it, but sadly, nothing ever was.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;So I left the Playdate community&lt;/a&gt;. Over the following months, I faced various forms of harassment: doxxing, unsavoury DMs, spam campaigns targeting my email, cell phone, and social media accounts, unfounded accusations—the list goes on. I can tell you, &lt;em&gt;this is not my idea of a fun time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You might think that after a year this would be old news. Sadly, it’s not. I’ve long since moved on with my life and kept creating—for platforms as exotic as the &lt;a href=&quot;/2025/01/05/dream-ride-for-sega-dreamcast-and-emulators/&quot;&gt;Sega Dreamcast&lt;/a&gt; and as familiar as &lt;a href=&quot;/2025/08/21/wormhole-for-perplexity-comet/&quot;&gt;the web&lt;/a&gt;. I’m proud of what I’ve achieved, and of the choices that allow me to keep doing what I do best, regardless of the people who try to put barriers in my way.&lt;/p&gt;

&lt;p&gt;While I continued creating &lt;a href=&quot;/2025/05/09/atari-jeff-minter-game-results-jam-llamasoft-and-st-format/&quot;&gt;award-winning games&lt;/a&gt;, the chance to build the game of my dreams came along—made easier by being an employee at a company that would handle funding, marketing, and the practicalities, freeing me to focus on doing my best work. It was a decision I didn’t take lightly, both because of potential ethical concerns and the fear of further harassment. I sought advice from close friends and had thoughtful discussions with several of them. One friend in particular told me they hadn’t heard of the company, so we didn’t discuss it further. That was back in May.&lt;/p&gt;

&lt;p&gt;I announced my first work with the company in July—again, this friend said nothing. Then, in mid-October, &lt;a href=&quot;https://www.linkedin.com/posts/mattsephton_super-happy-to-share-that-ive-joined-perplexity-activity-7384626318224617472-ZQJ-&quot;&gt;I announced my new permanent position&lt;/a&gt;, and that same friend suddenly went off the deep end. I asked what had changed since May, when they hadn’t heard of the company, and why nothing was said in July, when I first went public with my new work—yet now, in October, they were suddenly so angry. Their reply:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“One of my friends saw your post and sent it to me saying ‘oh no,’ which is how I found out. And then another friend (who you also know) also said ‘oh nooooooo.’”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, essentially, this friend had been incited into anger by others—the same social dynamic that fuelled the harassment a year ago. And the worst part? Those two mutual friends are key figures in the Playdate scene—the very people who once promised to address the harassment are now perpetuating it, a year on. I need to find a stronger word than &lt;em&gt;disappointing&lt;/em&gt;, but that will have to do for now.&lt;/p&gt;

&lt;p&gt;At this point, I’m letting things run their course and will continue to do what I do best: make games. I’m looking forward to you being able to play the next one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plus ça change—the more things change, the more they stay the same.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Have fun,&lt;br /&gt;
matt&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 29 Oct 2025 12:12:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/10/29/post-playdate-one-year-later/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/10/29/post-playdate-one-year-later/</guid>
        </item>
      
    
      
        <item>
          <title>Wormhole for Perplexity Comet</title>
          <description>&lt;p&gt;Surprise! My latest game, Wormhole, is included in the &lt;a href=&quot;https://www.perplexity.ai/comet&quot;&gt;Comet web browser&lt;/a&gt; from &lt;a href=&quot;https://www.perplexity.ai&quot;&gt;Perplexity&lt;/a&gt;. It started as an idea to replace the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dinosaur_Game&quot;&gt;Chrome Dino game&lt;/a&gt; and grew into something a bit more sophisticated and fun, and a lot more on brand.&lt;/p&gt;

&lt;p&gt;Big love to &lt;a href=&quot;https://x.com/henrymodis&quot;&gt;Henry Modisett&lt;/a&gt; and the great team over at Perplexity.&lt;/p&gt;

&lt;p&gt;And to &lt;a href=&quot;https://x.com/soleio&quot;&gt;Soleio&lt;/a&gt; for the hookup—thanks sensei! 🙌&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 2560/1896;&quot; videoid=&quot;IbDfo3bKvjo&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;The development of this game was very typical for me and my process: rapid prototyping, careful scoping, and focus on the central mechanic. Let’s dive in!&lt;/p&gt;

&lt;h2 id=&quot;prototype-1&quot;&gt;Prototype 1&lt;/h2&gt;

&lt;p&gt;This took the brief very literally and replaced Chrome Dino in size and scope. It fitted in the same area of the page and had a similar one button interaction. So, it was a simple game where you controlled the speed of a comet and had to avoid incoming space debris for as long as possible by using a dash mechanic. You could chain dashes and therefore control your acceleration and deceleration whilst balancing risk and reward. It was fun, but the team had bigger ideas. &lt;a href=&quot;https://youtu.be/qk7J0CLwX80&quot;&gt;Video of first prototype&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;prototype-2&quot;&gt;Prototype 2&lt;/h2&gt;

&lt;p&gt;Multiple members of the team independently proposed the idea of space golf/billiards, or snooker as I called it which raised a few eyebrows, by which time I had already prototyped it. The initial version proved to be fun, so it was full steam ahead.&lt;/p&gt;

&lt;p&gt;I set out to refine the game feel and figure out game progress. I’d been reading about procedural generation in Elite (thanks &lt;a href=&quot;https://elite.bbcelite.com&quot;&gt;Mark Moxon&lt;/a&gt;) and Mario Kart World (thanks Nintendo) and created something similar for my game. A whole universe of galaxies and planets to conquer! It worked well, but the traversal between galaxies and the overall structure didn’t add anything to the game. Zooming through the universe looked super cool! &lt;a href=&quot;https://youtu.be/CQR4NPkDQ18&quot;&gt;Video of second prototype&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;prototype-3&quot;&gt;Prototype 3&lt;/h2&gt;

&lt;p&gt;So, I started the galaxy generation again from scratch. At this point I had the feeling of existential dread that all developers are probably familiar with. I wanted to trash it all and start again, but instead I went out for dinner and talked it over with a close friend and fellow developer (thanks &lt;a href=&quot;https://bsky.app/profile/daveroberts.dev&quot;&gt;Dave&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Eventually I calmed down and settled on a never-ending belt of galaxies. The transitions became much shorter and sweeter, and the game feel was better than ever. At this point I think I was still coding in &lt;a href=&quot;https://love2d.org&quot;&gt;love2d&lt;/a&gt;. Things were locked down, so I ported the game to JavaScript using the &lt;a href=&quot;https://github.com/KilledByAPixel/LittleJS&quot;&gt;LittleJS&lt;/a&gt; framework. According to my notes the prototype was about 300 lines of code before I began the hard work of rounding it out into a game. &lt;a href=&quot;https://youtu.be/H_5MYCft1-I&quot;&gt;Video of third prototype&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;procedurally-generated&quot;&gt;Procedurally generated&lt;/h2&gt;

&lt;p&gt;Without giving too much away, the galaxies are procedurally generated with a handful of galaxy types and several other parameters and properties dictating the layout, rotating in a multi-layer but deterministic sequence. It was really fun to think through and implement.&lt;/p&gt;

&lt;p&gt;Planets can either attract and repel, gravity varies, slingshots are possible, trick shots are possible, hole-in-one is possible. Wormholes can help or hinder.&lt;/p&gt;

&lt;p&gt;The deterministic nature of the game means that everybody plays the same series of galaxies but at their own pace. And you can watch a replay of your shot if you get a suitably amazing black-hole-in-one, with a quick press of the R key (thanks &lt;a href=&quot;https://readonlymemory.com/the-making-of-sensible-soccer/&quot;&gt;Sensible Soccer&lt;/a&gt;). The game is theoretically never-ending, and the difficulty comes with carefully balanced stepped progression and cyclical repeating of the various game properties (thanks &lt;a href=&quot;https://en.wikipedia.org/wiki/Music_for_18_Musicians&quot;&gt;Steve Reich&lt;/a&gt;).&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;never-quite-made-it&quot;&gt;Never quite made it&lt;/h2&gt;

&lt;p&gt;If you’ve followed any of my developments you’ll know I’m quite happy to throw code away as quick as I can create it. I attach myself to the idea and execution rather than the code itself.&lt;/p&gt;

&lt;p&gt;So it’s fun to mention some things that never made it. As well as the realistic universe, there were some additional obstacle types that fell by the wayside, and the ability to export a video recording of your replay for sharing.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;finishing-touches&quot;&gt;Finishing touches&lt;/h2&gt;

&lt;p&gt;During prototyping I use geometric shapes: circles, rectangles, lines, and so on. The team at Perplexity then worked up visual designs (thanks &lt;a href=&quot;https://x.com/_erinmcknight&quot;&gt;Erin&lt;/a&gt;) and I implemented them as a combination of bitmaps, SVG for noise texture, CSS for round rects, and there are still arcs, circles, lines, and various fill types punching well above their weight. LittleJS (thanks &lt;a href=&quot;https://x.com/KilledByAPixel&quot;&gt;Frank&lt;/a&gt;) is a fantastic and very well optimised framework that I encourage all game devs to check out.&lt;/p&gt;

&lt;p&gt;Sound was initially synthesised using &lt;a href=&quot;https://github.com/KilledByAPixel/ZzFX&quot;&gt;ZzFX&lt;/a&gt; (thanks again &lt;a href=&quot;https://x.com/KilledByAPixel&quot;&gt;Frank&lt;/a&gt;), given LittleJS has built-in support, but they were eventually replaced with digital audio and music (thanks &lt;a href=&quot;https://x.com/nesodude&quot;&gt;neso&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The Comet launch page was designed by &lt;a href=&quot;https://x.com/eschadiol&quot;&gt;Escha Diol&lt;/a&gt;, product designer on Comet, who has been very supportive during this project. She’s a pleasure to work alongside.&lt;/p&gt;

&lt;p&gt;There are lots of details and a high level of polish in the game that are easily overlooked but are essential to the final feel: particles, parallax, keyboard control, replay, and more.&lt;/p&gt;

&lt;p&gt;Have fun with it!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 21 Aug 2025 16:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/08/21/wormhole-for-perplexity-comet/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/08/21/wormhole-for-perplexity-comet/</guid>
        </item>
      
    
      
        <item>
          <title>Donating my Playdate earnings to The Cybersmile Foundation</title>
          <description>&lt;p&gt;I’ve decided to donate all of my &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; earnings (my personal take-home, after &lt;a href=&quot;https://panic.com&quot;&gt;Panic&lt;/a&gt; and &lt;a href=&quot;https://stripe.com&quot;&gt;payment processor&lt;/a&gt; fees) to &lt;a href=&quot;https://www.cybersmile.org&quot;&gt;The Cybersmile Foundation&lt;/a&gt;, starting July 2025.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cybersmile is a multi-award-winning nonprofit dedicated to digital wellbeing and combating all forms of cyberbullying and online abuse. It’s registered as a charity in the UK and as a 501(c)3 nonprofit organization in the US.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having experienced online abuse myself—&lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;and received so little support that it ultimately drove me away from Playdate as a platform&lt;/a&gt;—this feels like the most constructive and meaningful way to turn that experience into something positive. I’d love to donate the full amount these games generate, but I can only give what actually reaches me.&lt;/p&gt;

&lt;p&gt;Be excellent to each other.&lt;/p&gt;

&lt;p&gt;Peace and love,&lt;br /&gt;
matt&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/cybersmile.png&quot; alt=&quot;IMG&quot; title=&quot;Receipt for donation to The Cybersmile Foundation&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 02 Aug 2025 11:18:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/08/02/donating-my-playdate-earnings-to-the-cybersmile-foundation/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/08/02/donating-my-playdate-earnings-to-the-cybersmile-foundation/</guid>
        </item>
      
    
      
        <item>
          <title>Abandoned project: Band-kun/Beatnik for Playdate</title>
          <description>&lt;p&gt;Back in November 2020 I was exploring the &lt;a href=&quot;https://en.wikipedia.org/wiki/PC-98&quot;&gt;PC-98&lt;/a&gt; back catalog, and stumbled across a strange game called &lt;a href=&quot;https://www.mobygames.com/game/155798/band-kun/&quot;&gt;Band-kun&lt;/a&gt;. Strange in that it’s a 1-bit black and white game on a platform that was capable of colour, and also because it’s a hybrid adventure/management/music/rhythm game. &lt;a href=&quot;/2020/12/16/band-kun-musician-simulator-1990-koei/&quot;&gt;I was smitten&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div id=&quot;carousel0&quot; class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0b&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0c&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0d&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0e&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0f&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel0&quot; id=&quot;0g&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0g&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0c&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0d&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0c&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0e&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0d&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0f&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0e&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0g&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;0f&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;0a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-01.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-01.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-02.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-02.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-03.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-03.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-04.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-04.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-05.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-05.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-06.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-06.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-07.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-07.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0b&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0c&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0d&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0e&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0f&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;0g&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 62.5%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}

.carousel__activator:nth-of-type(3):checked ~ .carousel__track {
  -webkit-transform: translateX(-200%);
          transform: translateX(-200%);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__slide:nth-of-type(3) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__controls:nth-of-type(3) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(3) {
  opacity: 1;
}

.carousel__activator:nth-of-type(4):checked ~ .carousel__track {
  -webkit-transform: translateX(-300%);
          transform: translateX(-300%);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__slide:nth-of-type(4) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__controls:nth-of-type(4) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(4) {
  opacity: 1;
}

.carousel__activator:nth-of-type(5):checked ~ .carousel__track {
  -webkit-transform: translateX(-400%);
          transform: translateX(-400%);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__slide:nth-of-type(5) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__controls:nth-of-type(5) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(5) {
  opacity: 1;
}

.carousel__activator:nth-of-type(6):checked ~ .carousel__track {
  -webkit-transform: translateX(-500%);
          transform: translateX(-500%);
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__slide:nth-of-type(6) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__controls:nth-of-type(6) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(6) {
  opacity: 1;
}

.carousel__activator:nth-of-type(7):checked ~ .carousel__track {
  -webkit-transform: translateX(-600%);
          transform: translateX(-600%);
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__slide:nth-of-type(7) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__controls:nth-of-type(7) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(7) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(3) {
  -webkit-transform: translateX(200%) translateZ(0);
          transform: translateX(200%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(4) {
  -webkit-transform: translateX(300%) translateZ(0);
          transform: translateX(300%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(5) {
  -webkit-transform: translateX(400%) translateZ(0);
          transform: translateX(400%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(6) {
  -webkit-transform: translateX(500%) translateZ(0);
          transform: translateX(500%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(7) {
  -webkit-transform: translateX(600%) translateZ(0);
          transform: translateX(600%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(3),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(3 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(4),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(4 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(5),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(5 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(6),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(6 {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(7),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(7 {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;#carousel0 .carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;/h2&gt;

&lt;p&gt;I was already developing for the &lt;a href=&quot;https://play.date/&quot;&gt;Playdate&lt;/a&gt;, a modern 1-bit platform, and it struck me as the perfect opportunity to create a remaster of the game. So, I set my sights on securing the licence. The original title was developed by Koei—Japan’s equivalent to Electronic Arts—a giant now known as Koei Tecmo, whose owners are worth hundreds of billions. The game itself is credited to one of those owners: Yoichi Erikawa, who used the pen name Ko Shibusawa. I had a feeling this wasn’t going to be easy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-playdate.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I published a thread about the game and my prototype &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1339232766861451278&quot;&gt;on Twitter&lt;/a&gt;, introducing the game to the West, which remains my most popular post and thread of all-time (~20 years, for me) at over 450K impressions. I also mirrored the thread as a &lt;a href=&quot;/2020/12/16/band-kun-musician-simulator-1990-koei/&quot;&gt;blog post&lt;/a&gt; which is no doubt an easier read.&lt;/p&gt;

&lt;p&gt;The idea for the remaster was to not remake the original game at all, but rather to take the vibe and bring it into the modern era. So there were no plans to use the original music, or perhaps even the &lt;a href=&quot;/2021/01/03/extracting-images-from-band-kun/&quot;&gt;original graphics&lt;/a&gt;. I would leverage modern device capabilities and input methods to create a totally new experience a million miles away from the limited original game from 1990.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;challenge-accepted&quot;&gt;Challenge Accepted&lt;/h2&gt;

&lt;p&gt;A couple of days later, 18th December 2020, &lt;a href=&quot;https://cabel.com&quot;&gt;Cabel Sasser&lt;/a&gt; of &lt;a href=&quot;https://panic.com&quot;&gt;Panic&lt;/a&gt; reached out:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Hey Matt, I love a good challenge—do you want me to actually try to make contact with someone at Koei? Regarding Band-Kun? (Philosophically, the idea of reviving a long-forgotten PC Koei title is just enormously interesting to me ahhahah)”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By 25th December 2020—thanks Santa!—Panic’s guy in Japan, Noby, had a breakthrough finding contact details and sent an email to Koei. Their reply came quickly on 27th December 2020 when a lovely person in Koei’s IP management department replied:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;they knew of the Playdate and were waiting patiently to pre-order&lt;/li&gt;
  &lt;li&gt;they had the licence for the Band-kun game (music to my ears!)&lt;/li&gt;
  &lt;li&gt;there was an outstanding question about the music rights&lt;/li&gt;
  &lt;li&gt;and some remaining business questions for Panic to answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project then became in need of a budget to be set: for both the licence and for me to build it. Even with this discussion happening in late December 2020, it was suggested that the game could feature in Season 2. And that, unfortunately, was the last I heard of it. Sad, and surprising, but true.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Not one to give up so easily I submitted the game twice, kind of, in pitches to Panic.&lt;/p&gt;

&lt;h2 id=&quot;open-pitch-band-kun&quot;&gt;Open Pitch: Band-kun&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;June 2022&lt;/li&gt;
  &lt;li&gt;to reignite the licence discussion&lt;/li&gt;
  &lt;li&gt;a reimagining of the original game for a modern device&lt;/li&gt;
  &lt;li&gt;as a team effort with musician and tools programmers; to hit a deadline&lt;/li&gt;
  &lt;li&gt;suggested budget was included&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cdn.gingerbeardman.com/files/playdate-pitch-2022-band-kun.pdf&quot;&gt;pitch pdf&lt;/a&gt; (191 KB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://cdn.gingerbeardman.com/files/playdate-pitch-2022-band-kun.pdf&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/abandoned-playdate-band-kun.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;On 1st May 2024 I sent a message to Panic stating that I was still interested in making the game and to check the status of the project, but never received a reply.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;season-2-pitch-beatnik&quot;&gt;Season 2 Pitch: Beatnik&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;July 2024&lt;/li&gt;
  &lt;li&gt;an all-new game&lt;/li&gt;
  &lt;li&gt;let’s forget about the IP&lt;/li&gt;
  &lt;li&gt;completely revised and redesigned&lt;/li&gt;
  &lt;li&gt;as a solo endeavour; I was confident I could complete the new scope myself&lt;/li&gt;
  &lt;li&gt;no budget was required&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cdn.gingerbeardman.com/files/playdate-pitch-2024-beatnik.pdf&quot;&gt;pitch pdf&lt;/a&gt; (185 KB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://cdn.gingerbeardman.com/files/playdate-pitch-2024-beatnik.pdf&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/abandoned-playdate-beatnik.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;gono-go&quot;&gt;Go/no-go&lt;/h2&gt;

&lt;p&gt;Neither of the pitches were successful. There was no further discussion of the licence from 2020.&lt;/p&gt;

&lt;p&gt;Regardless, I decided that I would continue working on the game and release it myself. This was the big project I was working on pretty much exclusively from May 2024 to &lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;October 2024&lt;/a&gt;. You can see elements of it in my &lt;a href=&quot;/2025/03/11/old-codes-new-releases-for-playdate/&quot;&gt;New World&lt;/a&gt; and &lt;a href=&quot;https://gingerbeardman.itch.io/new-world&quot;&gt;Band-o-matic&lt;/a&gt; tech demos.&lt;/p&gt;

&lt;p&gt;In August 2024, I took a two-week break from working on Beatnik to develop &lt;a href=&quot;/2024/10/08/bender-2-bend-harder-for-playdate/&quot;&gt;Bender 2: Bend Harder&lt;/a&gt;, an expanded version of a game I originally made in 2012. As part of that project, I integrated some of the tooling and library code I had built for Beatnik to test and validate a few of the technologies and concepts. &lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;And that was the end of that&lt;/a&gt;.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 11 May 2025 16:58:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/05/11/abandoned-project-bandkun-beatnik-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/05/11/abandoned-project-bandkun-beatnik-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Atari/Jeff Minter game jam results, Llamasoft, and ST Format</title>
          <description>&lt;p&gt;So, my game &lt;a href=&quot;https://gingerbeardman.itch.io/herd-nerd&quot;&gt;HERD NERD&lt;/a&gt; is a winner in the “&lt;em&gt;I, REBEL&lt;/em&gt;” game jam, hosted by Atari and Jeff Minter.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We are delighted to let you know after hours of play and deliberation - Jeff Minter himself chose your game as THIRD PLACE WINNER&lt;/p&gt;

  &lt;p&gt;Your game stood out in all the right ways: creative, clever, weird and totally nailing the theme. The team (and the judges!) were blown away by your take on the theme and your execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✨ &lt;em&gt;What an honour!&lt;/em&gt; ✨&lt;/p&gt;

&lt;p&gt;All three winners receive the same prize, but honestly I am more excited to hear why Jeff, Giles, and Jason liked my game. So many nice words to spur me on!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-results&quot;&gt;The Results&lt;/h2&gt;

&lt;p&gt;You can hear more about the game jam and the winning games on the latest Atari podcast episode on YouTube or your favourite podcast listening point. You’ll also learn a bit about the famous &lt;a href=&quot;https://en.wikipedia.org/wiki/Superlambanana&quot;&gt;Superlambanana&lt;/a&gt; sculpture and the infamous &lt;a href=&quot;https://en.wikipedia.org/wiki/Sven_B%C3%B8mw%C3%B8llen&quot;&gt;Sven Bømwøllen&lt;/a&gt; video game. You have been warned!&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;GeHie-2Jvlw&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;iframe allow=&quot;autoplay *; encrypted-media *; fullscreen *; clipboard-write&quot; frameborder=&quot;0&quot; height=&quot;175&quot; style=&quot;width:100%;max-width:660px;overflow:hidden;border-radius:10px;&quot; sandbox=&quot;allow-forms allow-popups allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation-by-user-activation&quot; src=&quot;https://embed.podcasts.apple.com/gb/podcast/episode-54-our-favorite-i-rebel-game-jam-games-w-llamasoft/id1585430874?i=1000706983440&quot;&gt;&lt;/iframe&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;herd-nerd&quot;&gt;HERD NERD&lt;/h2&gt;

&lt;p&gt;You can download and play &lt;a href=&quot;https://gingerbeardman.itch.io/herd-nerd&quot;&gt;HERD NERD&lt;/a&gt; for free/&lt;a href=&quot;https://en.wikipedia.org/wiki/PWYC&quot;&gt;PWYC&lt;/a&gt; on Mac and PC. So check it out! Have fun.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;KfWiaGyMB24&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;back-in-the-day&quot;&gt;Back in the day&lt;/h2&gt;

&lt;p&gt;It’s July 1991 and I’ve just walked back from Lewis Meeson’s newsagent to my family home clutching &lt;a href=&quot;https://archive.org/details/atari-st-format-issue-024/page/1/mode/2up&quot;&gt;the latest monthly ST FORMAT&lt;/a&gt;, issue 24. I’d browsed the magazine in-store to make sure it was worth £2.95 of my hard-earned pocket money, and was eager to try out the software included on the 3.5” floppy disk. This was pre-internet and that was the easiest way of getting hold of a selection of new software. The same thing applied to Amiga, &lt;a href=&quot;/2025/03/28/macintosh-magazine-media-1-million-files/&quot;&gt;Macintosh&lt;/a&gt;, PC, and more.&lt;/p&gt;

&lt;p&gt;Today I dug out &lt;em&gt;my actual magazine&lt;/em&gt; from storage and my nostalgia dial went all the way &lt;a href=&quot;https://en.wikipedia.org/wiki/Up_to_eleven&quot;&gt;up to 11&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://archive.org/details/atari-st-format-issue-024/page/1/mode/2up&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/st-format-24-cover.jpg&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Llamatron&quot;&gt;Llamatron&lt;/a&gt; was my first encounter with Jeff Minter and his weird and wonderful type of game. I played it a lot, mostly in 2-player with the droid or other members of my family. Enemies like sentient cans of cola or screaming Mandelbrot patterns are scorched into my memory forever more.&lt;/p&gt;

&lt;p&gt;But it wasn’t just Llamatron that was so great in this issue, I also remember using the &lt;a href=&quot;https://www.atariuptodate.de/en/11414/revenge-document-display-system&quot;&gt;Revenge&lt;/a&gt; document displayer (with no internet we used to read a lot of text files that were included on the disks, like the Llamatron manual and readme about it being distributed in a new-fangled way known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Shareware&quot;&gt;Shareware&lt;/a&gt;). And also &lt;a href=&quot;https://www.atariuptodate.de/en/1562/little-green-selector&quot;&gt;Little Green Selector&lt;/a&gt; which replaced the standard file selector with one that had fully-featured file manager functionality, though eventually I migrated to the even more amazing &lt;a href=&quot;https://www.atariuptodate.de/en/1564/universal-item-selector&quot;&gt;Universal Item Selector III&lt;/a&gt; which was &lt;a href=&quot;http://aicq.gokmase.com/file_sel/index.htm&quot;&gt;one of many such replacements&lt;/a&gt;. It really was a different era.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://archive.org/details/atari-st-format-issue-024/page/38/mode/2up&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/st-format-24-disk-spread.jpg&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elsewhere in the magazine is a list of Jeff’s favourite games of all time (as of mid-1991). I love that he put his own game at number 1. And then to also include 2 more of his games. What a rock star! Click the image to zoom. Below you’ll find a full list of games with links to read more.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://archive.org/details/atari-st-format-issue-024/page/74/mode/2up&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/st-format-24-yak-faves.jpg&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-yaks-favourite-games-of-all-time-1991&quot;&gt;A yak’s favourite games (of all time), 1991&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/3604/llamatron-2112/&quot;&gt;Llamatron&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/1237/starglider-ii/&quot;&gt;Starglider 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/683/lemmings/&quot;&gt;Lemmings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/10977/damocles-mercenary-ii/&quot;&gt;Damocles: Mercenary II&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/1993/powermonger/&quot;&gt;PowerMonger&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/134/captain-blood/&quot;&gt;Captain Blood&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/147905/defender-ii/&quot;&gt;Defender 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/19494/virus/&quot;&gt;Virus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/3481/gauntlet-ii/&quot;&gt;Gauntlet 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/5628/escape-from-the-planet-of-the-robot-monsters/&quot;&gt;Escape from the Planet of the Robot Monsters&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/181422/super-grid-runner/&quot;&gt;Super Grid Runner&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/1087/arkanoid/&quot;&gt;Arkanoid&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/1426/the-game-of-harmony/&quot;&gt;E-Motion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/1324/elite/&quot;&gt;Elite&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/782/stunt-track-racer/&quot;&gt;Stunt Car Racer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/834/dungeon-master/&quot;&gt;Dungeon Master&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/14951/plutos/&quot;&gt;Plutos&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/2468/time-bandit/&quot;&gt;Time Bandit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mobygames.com/game/14094/flight-simulator-ii/&quot;&gt;Flight Simulator 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.modula.org.uk/atari-st-disks-index/?atari_disk_search=mandy&quot;&gt;Trendy Handy Randy Hendy Bendy Mandy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 09 May 2025 17:03:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/05/09/atari-jeff-minter-game-results-jam-llamasoft-and-st-format/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/05/09/atari-jeff-minter-game-results-jam-llamasoft-and-st-format/</guid>
        </item>
      
    
      
        <item>
          <title>Abandoned project: Soccer for Playdate</title>
          <description>&lt;p&gt;On September 30th, 2023, I was sitting in the cinema &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1708437276756214147&quot;&gt;waiting for an anniversary screening&lt;/a&gt; of Talking Heads &lt;em&gt;“&lt;a href=&quot;https://en.wikipedia.org/wiki/Stop_Making_Sense&quot;&gt;Stop Making Sense&lt;/a&gt;”&lt;/em&gt; to begin when I got a message from &lt;a href=&quot;https://panic.com&quot;&gt;Panic&lt;/a&gt;. They asked if I was familiar with Sensible Soccer. Naturally, I was—I’ve played it since its release in 1992, as man and boy. Back in 2000, I’d even made my own arcade-style take on it called Simple Soccer, and in 2002 I designed an &lt;a href=&quot;/2002/05/23/sensible-soccer-t-shirt/&quot;&gt;official Sensible Soccer T-shirt&lt;/a&gt; that was sold on the high street. Panic had no idea about any of this, but luck works in funny ways sometimes.&lt;/p&gt;

&lt;p&gt;Panic’s idea was to make a soccer game for &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt;, tied in as a promotional companion to the soccer-infused first-person slice-of-life game &lt;a href=&quot;https://en.wikipedia.org/wiki/Despelote&quot;&gt;Despelote&lt;/a&gt; (out today—1st May, 2025). Very cool.&lt;/p&gt;

&lt;p&gt;I was super keen, as you’d imagine, and quickly got to work on a &lt;a href=&quot;https://gingerbeardman.itch.io/prototypes-for-playdate&quot;&gt;prototype&lt;/a&gt; (download at the link). It let you move around the pitch, zoom in and out, and switch between different pitch surfaces. I sent it off and asked for a budget and scope. With the expectation set that the project was going forwards and while waiting for a reply, I kept going: I got the ball moving (using the same sort of ball movement trick I first solved 25 years ago and more recently reused for &lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Fore! Track&lt;/a&gt;), and had two AI-controlled teams running around the pitch, tracking the ball using the classic Sensible Soccer &lt;a href=&quot;https://readonlymemory.com/the-making-of-sensible-soccer/&quot;&gt;grid system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But I never heard back about the budget. So I stopped—just before adding goal-scoring. It would’ve been so cool.&lt;/p&gt;

&lt;p&gt;Lesson learned. I now always ask for a contract upfront and of course don’t do spec work. If a client wants me to build something, they need to commit—and at the very least, meet me on the halfway line.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/soccer-playdate.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 01 May 2025 14:34:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/05/01/abandoned-project-soccer-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/05/01/abandoned-project-soccer-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Abandoned project: firework builder puzzle game</title>
          <description>&lt;p&gt;I plan to occasionally list abandoned projects that I’ve decided not to take any further.&lt;/p&gt;

&lt;p&gt;This one is a prototype for a “firework builder” puzzle game. I was calling it Hanabi, the Japanese word for firework, but I’m not sure I would have stuck with that for the final name.&lt;/p&gt;

&lt;p&gt;It’s a visual programming-based puzzle video game along the lines of &lt;a href=&quot;https://en.wikipedia.org/wiki/Human_Resource_Machine&quot;&gt;Human Resource Machine&lt;/a&gt; and influenced by block-based visual programming language &lt;a href=&quot;https://en.wikipedia.org/wiki/Scratch_(programming_language)&quot;&gt;Scratch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I submitted it to the Draknek New Voices Puzzle Grant 2024, but was not selected. At the time of submission the core game logic had been proven, with a dozen or so block types supported, and I was learning how to program shaders as I had a very specific way I wanted to present the final firework animation. You can see the paper texture that I was generating using a shader in the video below. I had a dozen or so puzzles designed, including a heart shape which takes some thinking and combining of logic blocks to achieve!&lt;/p&gt;

&lt;p&gt;Whilst the prototype was an iOS app—mostly to benefit from rapid prototyping using SwiftUI and to get touch control and easy list management for free—the final game could have been on any platform. The challenge would be user interface, followed by puzzles and visual design.&lt;/p&gt;

&lt;p&gt;I gave up on the idea for a number of reasons, including but not limited to &lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;harassment&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;video-demonstration&quot;&gt;Video Demonstration&lt;/h2&gt;

&lt;p&gt;Below is the video I submitted with my entry, dated 2024-10-07. I narrate and run through the concept, complete example puzzles, and talk about the “woodblock print” style of fireworks I was planning and in the process of implementing.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 1124/2436;&quot; videoid=&quot;APMvQ-jVTwM&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 23 Apr 2025 21:39:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/04/23/abandoned-project-firework-builder-puzzle-game/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/04/23/abandoned-project-firework-builder-puzzle-game/</guid>
        </item>
      
    
      
        <item>
          <title>When Playdate Stopped Being Fun</title>
          <description>&lt;p&gt;For almost six years, &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; (a little handheld gaming device with a crank input and 1-bit screen) was a space where I did some of my most creative and personal work. I embraced its quirks, shipped over twenty releases, and explored what a tiny, constrained device could do. It brought me joy, challenge, and a sense of purpose.&lt;/p&gt;

&lt;p&gt;But over time, that feeling changed. Following a difficult incident in October 2024 involving targeted harassment—admitted to by &lt;!-- Scizzorz --&gt;the developer responsible, but met with no meaningful follow-up from the community moderators and no reply at the time of writing from &lt;a href=&quot;https://www.panic.com&quot;&gt;Panic&lt;/a&gt;—I began to feel increasingly disconnected from the scene. I gave it time, hoped things might shift, but ultimately the silence made it hard to keep building with the same heart.&lt;/p&gt;

&lt;p&gt;So, I’m stepping back. Not dramatically—just with clarity. Right now, this isn’t the environment I can thrive in. If that changes, I’d be happy to return. For now, I want to leave a record of what I made. I’m proud of all of it. I’ll continue as a full-time indie developer, but in another castle.&lt;/p&gt;

&lt;p&gt;Be excellent to each other. And have fun.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;released-projects&quot;&gt;Released Projects&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-03&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/today&quot;&gt;Today&lt;/a&gt; (the first Playdate thing sold on itch.io)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-04&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/horse-race&quot;&gt;Horse Race&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-04&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/audition&quot;&gt;Audition&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-04&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/prototypes-for-playdate&quot;&gt;Prototypes&lt;/a&gt; multi-pack&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-04&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/daily-driver&quot;&gt;Daily Driver&lt;/a&gt; (tech demo)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-05&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/circular&quot;&gt;Circular&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2022-05&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/st-din-playdate-font&quot;&gt;ST-DIN&lt;/a&gt; and &lt;a href=&quot;https://gingerbeardman.itch.io/supermini-playdate-font&quot;&gt;Supermini&lt;/a&gt; fonts&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-04&lt;/code&gt; &lt;a href=&quot;https://play.date/games/sparrow-solitaire/&quot;&gt;Sparrow Solitaire&lt;/a&gt; (with &lt;a href=&quot;https://vogelscript.itch.io&quot;&gt;Mac Vogelsang&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-05&lt;/code&gt; &lt;a href=&quot;/2023/05/10/piskel-for-playdate/&quot;&gt;Piskel for Playdate&lt;/a&gt; (desktop pixel art app)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-07&lt;/code&gt; &lt;a href=&quot;https://github.com/gingerbeardman/mandala&quot;&gt;Mandala&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-08&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/strategies&quot;&gt;Strategies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-08&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/datediff&quot;&gt;DateDiff&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-08&lt;/code&gt; &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;YOYOZO&lt;/a&gt; (“Best Games of 2023”, &lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;Ars Technica&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-10&lt;/code&gt; &lt;a href=&quot;https://mouflon-cloud.itch.io/kye&quot;&gt;Kye&lt;/a&gt; (with &lt;a href=&quot;https://mouflon-cloud.itch.io&quot;&gt;Jan Martinek&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-10&lt;/code&gt; &lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Super ICARUS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-12&lt;/code&gt; &lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;Fore! Track&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-12&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/see-the-sky&quot;&gt;See the Sky&lt;/a&gt; (with &lt;a href=&quot;https://twitter.com/thoruman&quot;&gt;Thoru Yamamoto&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2024-05&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/rorschach&quot;&gt;Rorschach&lt;/a&gt; (featuring mouse control)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2024-10&lt;/code&gt; &lt;a href=&quot;https://play.date/games/bender-2-bend-harder/&quot;&gt;Bender 2: Bend Harder&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2025-03&lt;/code&gt; &lt;a href=&quot;https://gingerbeardman.itch.io/shark-turtle&quot;&gt;Shark Turtle&lt;/a&gt;, originally created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2023-06&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-teaser.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;cancelled-projects&quot;&gt;Cancelled Projects&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Aero Club&lt;/strong&gt;—Flight school simulation inspired by Mode 7 and Pilotwings&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Beatnik&lt;/strong&gt;—Rhythm game with interactive music and beat-matched dynamic visuals&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cosmic Trash&lt;/strong&gt;—Arcade action puzzle with realtime ray-traced graphics&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Daily Driver&lt;/strong&gt;—60fps arcade racing with pre-rendered graphics (reborn as &lt;a href=&quot;/2025/01/05/dream-ride-for-sega-dreamcast-and-emulators/&quot;&gt;Dream Ride&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Koatari&lt;/strong&gt;—Pachinko-style arcade game with pinball-inspired visuals, running up to 120fps&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mole Hole&lt;/strong&gt;—A modern remake of Thoru Yamamoto’s escape-maze concept&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/molehole.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Daily Driver&lt;/strong&gt; won “Outstanding Technical Achievement (SDK)” at the&lt;a href=&quot;https://playdate-wiki.com/wiki/The_2022_Playdate_Community_Awards&quot;&gt; 2022 Community Awards&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sparrow Solitaire&lt;/strong&gt; won “Best Puzzle Game” at the &lt;a href=&quot;https://playdate-wiki.com/wiki/The_2023_Playdate_Community_Awards&quot;&gt;2023 Community Awards&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YOYOZO&lt;/strong&gt; won “Best Arcade Game” at the &lt;a href=&quot;https://playdate-wiki.com/wiki/The_2023_Playdate_Community_Awards&quot;&gt;2023 Community Awards&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YOYOZO&lt;/strong&gt; was named one of the “Best Games of 2023” by &lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;Ars Technica&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bender 2: Bend Harder&lt;/strong&gt; was nominated for “Best Arcade Game” at the &lt;a href=&quot;https://playdate-wiki.com/wiki/The_2024_Playdate_Community_Awards&quot;&gt;2024 Community Awards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;em&gt;Thanks to JM, JS, MR, PP, SC for feedback on versions of this post.&lt;/em&gt;
&lt;br /&gt;
&lt;em&gt;Panic were sent a draft of this post ahead of publication.&lt;/em&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 15 Apr 2025 21:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/04/15/when-playdate-stopped-being-fun/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/04/15/when-playdate-stopped-being-fun/</guid>
        </item>
      
    
      
        <item>
          <title>Shark Turtle: a modern version of SameGame/MaciGame</title>
          <description>&lt;p&gt;I’m releasing an expanded version of my game Shark Turtle for macOS and Windows. Grab it at itch: &lt;a href=&quot;https://gingerbeardman.itch.io/shark-turtle-desktop/&quot;&gt;gingerbeardman.itch.io/shark-turtle-desktop/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result is a feature-rich, native desktop version of SameGame with fast calculation, animated block removal, mouse/keyboard control, incremental scoring, variable grid sizes each with their own high score table, multi-level undo, lots of options, and great music. It’s a lot of fun and ideal to play little-by-little when you have a spare moment, as you dictate the pace of the game turn-by-turn.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sharkturtle-macos-lite.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;about-the-icon&quot;&gt;About the icon&lt;/h2&gt;

&lt;p&gt;I couldn’t find the exact licence for Google’s Emoji Kitchen, it’s either &lt;a href=&quot;https://github.com/googlefonts/noto-emoji/blob/main/LICENSE&quot;&gt;SIL as part of the Noto font&lt;/a&gt; or &lt;a href=&quot;https://developers.googleblog.com/en/updates-to-emoji-new-characters-new-animation-new-color-customization-and-more/&quot;&gt;CC BY 4.0&lt;/a&gt;. But I did find a &lt;a href=&quot;https://github.com/googlefonts/noto-emoji/issues/151#issuecomment-318418911&quot;&gt;comment&lt;/a&gt; by a Google staffer saying that it would be a good idea to draw a custom version that was less generic—I read that as unique and yours—so that’s exactly what I did. There was no choice but to do this, as I needed a vector version to generate an 1024×1024px icon. I like to think that with the raised eyebrow and slight smirk there’s a bit more personality in my version.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sharkturtle-icon.png&quot; alt=&quot;IMG&quot; title=&quot;My vector version of Google Emoji Kitchen’s “Shark Turtle”&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;whats-in-a-name&quot;&gt;What’s in a name?&lt;/h2&gt;

&lt;p&gt;This concept was originally released as &lt;a href=&quot;https://web.archive.org/web/20230507124114/http://www.asahi-net.or.jp:80/~KY6K-MRB/chainsht.htm&quot;&gt;Chain Shot!&lt;/a&gt; in 1985 by 森辺訓章 Kuniaki Moribe “Morisuke” and went on to become very popular, mostly through a version known as さめがめ SameGame. The game was at one time &lt;a href=&quot;/2023/08/19/fake-steve-jobs-and-letters-from-bill-g/#samegame&quot;&gt;more popular than Tetris in Japan&lt;/a&gt; and even made its way onto consoles like the &lt;a href=&quot;https://retro-gamer.jp/?p=10059&quot;&gt;Super Famicom&lt;/a&gt; and even as recent as &lt;a href=&quot;https://www.mobygames.com/game/55440/pop-em-drop-em-samegame/&quot;&gt;Wii&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In English we pronounce the name as it is spelled: same game. But in Japanese it sounds just like the words “same” さめ (shark) and “game” がめ (sea turtle). A short leap from SameGame to Shark Turtle.&lt;/p&gt;

&lt;p&gt;Perhaps the most well known version of the concept, &lt;a href=&quot;/2023/05/04/macigame-user-created-graphics/&quot;&gt;MaciGame&lt;/a&gt; まきがめ also riffed on this. I’m not sure of the exact meaning, but I like to think it’s a clever double meaning of something cool in Japanese and it also being a game for Macintosh.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/macigamekoma-01-usa-chan.png#pixel&quot; alt=&quot;PNG&quot; title=&quot;MaciGame’s classic default usa-chan tileset&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;recovering-tile-sets&quot;&gt;Recovering tile sets&lt;/h2&gt;

&lt;p&gt;I’d previously recovered a range of tile sets for a download pack I uploaded to &lt;a href=&quot;https://macintoshgarden.org/games/macigame&quot;&gt;Macintosh Garden&lt;/a&gt;, but that was done in the Classic Macintosh environment so I needed to redo it on modern macOS to be able to extract the images easily.&lt;/p&gt;

&lt;p&gt;MaciGame supported custom tile sets in three formats:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;SameGameFormat (160×64, from the PC-98 version of the game)&lt;/li&gt;
  &lt;li&gt;SameGameFormat2 (192×64, includes additional background tiles)&lt;/li&gt;
  &lt;li&gt;MaruSameFormat (256×65, includes connected variations and alternate palettes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tile sets were popular &lt;a href=&quot;/2023/05/04/macigame-user-created-graphics/&quot;&gt;user created content&lt;/a&gt; for 1990s Macintosh fans, given how easy it was to load up a paint app or ResEdit. They were made available for free download at online repositories like &lt;a href=&quot;https://en.wikipedia.org/wiki/Nifty_Corporation&quot;&gt;NIFTY-Serve&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Info-Mac&quot;&gt;Info-Mac&lt;/a&gt;, and on magazine cover mounted media around the world. I found several unique tile sets in my &lt;a href=&quot;/2025/03/28/macintosh-magazine-media-1-million-files/&quot;&gt;Macintosh Magazine Media&lt;/a&gt; archive of vintage CD-ROMs.&lt;/p&gt;

&lt;p&gt;The main online source of these is at: &lt;a href=&quot;https://www.vector.co.jp/vpack/filearea/osx/game/puzzle/makigame/&quot;&gt;vector.co.jp/vpack/filearea/osx/game/puzzle/makigame/&lt;/a&gt; and I automated the clicking of the download buttons using a &lt;a href=&quot;https://gist.github.com/gingerbeardman/47bfd8f6b76a7f33a6262b7998994416&quot;&gt;temporary user script&lt;/a&gt; (gist) to redirect to the download page and then click the button. I use &lt;a href=&quot;https://apps.apple.com/gb/app/pageextender-for-safari/id1457557274?mt=12&quot;&gt;PageExtender&lt;/a&gt; for such things. I could have gone one level deeper by automating the clicking of all the items on the list page, but I quite like clicking through long lists.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/47bfd8f6b76a7f33a6262b7998994416&quot;&gt;user script at gist.github.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can expand these esoteric archives with &lt;a href=&quot;https://theunarchiver.com&quot;&gt;The Unarchiver&lt;/a&gt;. I needed to confirm MacOS Japanese encoding for the filenames that it was unable to heuristically determine. Read more about the madness of &lt;a href=&quot;/2022/03/31/working-with-classic-macintosh-text-encodings-in-the-age-of-unicode/&quot;&gt;classic Macintosh text encodings in the pre-Unicode age&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we can convert the PICT resources we’re after with &lt;a href=&quot;https://github.com/jsummers/deark&quot;&gt;deark&lt;/a&gt;. Deark doesn’t have a recursive mode, so we need to wrap it in a one-liner:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find . -type f -print0 | xargs -0 -I {} deark {} -k -od /destination/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I verified those and &lt;a href=&quot;https://discmaster.textfiles.com/search?family=image&amp;amp;widthMin=160&amp;amp;heightMin=64&amp;amp;widthMax=160&amp;amp;heightMax=64&amp;amp;dedup=dedup&amp;amp;sortBy=itemid&amp;amp;pageNum=0&quot;&gt;found&lt;/a&gt; &lt;a href=&quot;https://discmaster.textfiles.com/search?family=image&amp;amp;widthMin=192&amp;amp;heightMin=64&amp;amp;widthMax=192&amp;amp;heightMax=64&amp;amp;dedup=dedup&amp;amp;sortBy=itemid&amp;amp;pageNum=0&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;https://discmaster.textfiles.com/search?family=image&amp;amp;widthMin=256&amp;amp;heightMin=65&amp;amp;widthMax=256&amp;amp;heightMax=65&amp;amp;dedup=dedup&amp;amp;sortBy=itemid&amp;amp;pageNum=0&quot;&gt;others&lt;/a&gt; &lt;a href=&quot;https://discmaster.textfiles.com/search?family=image&amp;amp;detection=PICT%2FSaMe&amp;amp;dedup=dedup&amp;amp;sortBy=itemid&amp;amp;pageNum=0&quot;&gt;using DiscMaster&lt;/a&gt;. A few stranglers found on the web brought the grand total to 320 tile sets.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;de-duplicating&quot;&gt;De-duplicating&lt;/h2&gt;

&lt;p&gt;It was obvious that there were some duplicates, so what to do? My first thought was to optimise all images equally, I used &lt;a href=&quot;https://github.com/fhanau/Efficient-Compression-Tool&quot;&gt;ect&lt;/a&gt; command line tool for this purpose. After that, still on the command line, we can do a quick de-dupe using the &lt;a href=&quot;https://github.com/adrianlopezroche/fdupes&quot;&gt;fdupes&lt;/a&gt; tool. This helped me get rid of a bunch, but there were still some hanging around.&lt;/p&gt;

&lt;p&gt;I wanted to compare files at a pixel level, so wrapped &lt;a href=&quot;https://github.com/ImageMagick/ImageMagick&quot;&gt;imagemagick&lt;/a&gt; in &lt;a href=&quot;https://gist.github.com/gingerbeardman/31c2eabf4c39ebad0ceb9c6265afd5a6&quot;&gt;a shell script&lt;/a&gt; (gist). We compare each image with every other image. I tried adding pre-checks to the script but they slowed it down and removed the ability for it to run in parallel. Keep it simple wins again.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/47bfd8f6b76a7f33a6262b7998994416&quot;&gt;shell script at gist.github.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;organising&quot;&gt;Organising&lt;/h2&gt;

&lt;p&gt;For organisation sake I wanted to verify and categorise the dimensions of each image. I created &lt;a href=&quot;https://gist.github.com/gingerbeardman/99585e86d9a6ed321a73cc5f6ab247a2&quot;&gt;a shell script to tag images of specific sizes with Finder colours&lt;/a&gt; (gist). I noticed that some converted images were one pixel wider than expected, it turns out that this is a quirk in how those specific image were composed. So I coloured them red and edited them by hand after the fact.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/47bfd8f6b76a7f33a6262b7998994416&quot;&gt;shell script at gist.github.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;all-tile-sets&quot;&gt;All tile sets&lt;/h2&gt;

&lt;p&gt;Here’s a video of my 5 tile sets plus the 320 classic user created tile sets. &lt;em&gt;Gotta catch ‘em all!&lt;/em&gt;&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 5/3;&quot; videoid=&quot;pbWV13BNloA&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;playdate&quot;&gt;Playdate&lt;/h2&gt;

&lt;p&gt;I originally wrote a version of &lt;a href=&quot;/2025/03/11/old-codes-new-releases-for-playdate/&quot;&gt;Shark Turtle for Playdate&lt;/a&gt; back in 2023 and released it earlier this month. The desktop version of the game is expanded and enhanced in the way that desktop apps can be. Those features took a bunch more work and I’ve undoubtedly been working on the platform specific stuff far more than I did on the core of the game.&lt;/p&gt;

&lt;p&gt;Buyers of the Shark Turtle for Playdate get the desktop version for free! Head to &lt;a href=&quot;https://itch.io/s/150167/shark-turtle-double-dip&quot;&gt;this bundle&lt;/a&gt;.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 01 Apr 2025 18:44:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/04/01/shark-turtle-a-modern-version-of-samegame-and-macigame/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/04/01/shark-turtle-a-modern-version-of-samegame-and-macigame/</guid>
        </item>
      
    
      
        <item>
          <title>Enhanced sfxr for Love2D</title>
          <description>&lt;p&gt;I’ve made a bunch of usability and quality of life changes to the &lt;a href=&quot;https://love2d.org/wiki/sfxr.lua&quot;&gt;sfxr.lua&lt;/a&gt; demo app.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;fix: getDirectoryItems (from a PR)&lt;/li&gt;
  &lt;li&gt;fix: off by one sample length error (from a PR)&lt;/li&gt;
  &lt;li&gt;fix: space bar was not playing the sound&lt;/li&gt;
  &lt;li&gt;fix: selected wave form was being ignored (sounds were always square wave)&lt;/li&gt;
  &lt;li&gt;fix: loaded wave form not updating the interface (but sound was playing correctly)&lt;/li&gt;
  &lt;li&gt;add: clone method added to sfxr.lua&lt;/li&gt;
  &lt;li&gt;add: history form with list of previous sounds, save current, and undo/redo&lt;/li&gt;
  &lt;li&gt;add: “play on changes” so that any time you adjust a sound it plays automatically&lt;/li&gt;
  &lt;li&gt;add: keyboard navigation in file picker (A–Z: jump to files, Enter: choose, Esc: close picker)&lt;/li&gt;
  &lt;li&gt;add: window title reflects the most recent loaded/saved file&lt;/li&gt;
  &lt;li&gt;add: window title and filename reflects last operation&lt;/li&gt;
  &lt;li&gt;add: file selector shows data directory path&lt;/li&gt;
  &lt;li&gt;add: unified save directory across platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can get it at: &lt;a href=&quot;https://gingerbeardman.itch.io/enhanced-sfxr-for-love2d&quot;&gt;gingerbeardman.itch.io/enhanced-sfxr-for-love2d&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At some point I’ll fork the project on GitHub and file some PRs with my changes, but the repo for it seems very dead so I’ll wait until I hear back from the owner. Source code is at the above link.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sfxr-lua.png&quot; alt=&quot;IMG&quot; title=&quot;“Enhance!”&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 11 Mar 2025 18:23:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/03/11/enhanced-sfxr-for-love2d/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/03/11/enhanced-sfxr-for-love2d/</guid>
        </item>
      
    
      
        <item>
          <title>Old Codes, New Releases for Playdate</title>
          <description>&lt;p&gt;As I sadly move away from game dev on Playdate, I’ve released a couple of interesting old things…&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;shark-turtle&quot;&gt;SHARK TURTLE&lt;/h2&gt;

&lt;p&gt;This is a version of &lt;a href=&quot;https://en.wikipedia.org/wiki/SameGame&quot;&gt;SameGame&lt;/a&gt; (さめがめ) originally released under the name &lt;a href=&quot;https://blog.gingerbeardman.com/2023/05/24/ordering-photocopies-from-japans-national-library/&quot;&gt;CHAIN SHOT&lt;/a&gt; in 1985 by Kuniaki “Morisuke” Moribe for Fujitsu FM-8 home computer. The concept is as old as Tetris, perhaps even older, and at one time SameGame in its many guises was more popular than Tetris in Japan. One version had an active &lt;a href=&quot;/2023/05/04/macigame-user-created-graphics/&quot;&gt;modding scene&lt;/a&gt; and some had &lt;a href=&quot;/2023/08/19/fake-steve-jobs-and-letters-from-bill-g/#samegame&quot;&gt;strategy guide books&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was submitted and rejected in the first wave of submissions to Playdate Catalog. At one point the plan was to wrap this in a theme/concept and give it the same sort of love that resulted in the great experiences of my other games like YOYOZO, Fore! Track, Bender 2: Bend Harder, but for one reason or another it never happened.&lt;/p&gt;

&lt;p&gt;What is here is a fully-playable, feature-rich, albeit “no frills” version of SameGame with fast updates, solid controls, and great music. It’s a lot of fun and great to play little-by-little when you have a spare moment, as you dictate the pace and progress of the game turn-by-turn.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/shark-turtle&quot;&gt;gingerbeardman.itch.io/shark-turtle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/old-playdate-shark-turtle.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;new-world&quot;&gt;NEW WORLD&lt;/h2&gt;

&lt;p&gt;This is an interactive music track where you’re the DJ. You control various instruments and vocals, doing live mixing of the track. It’s really fun to play with!&lt;/p&gt;

&lt;p&gt;It is a technology demo that was put together as part of a pitch for a game. Whilst the game never came to be, an improved version of this technology went on to be used in Bender 2: Bend Harder for the dynamic background patterns that animate to the beat of the music.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/new-world&quot;&gt;gingerbeardman.itch.io/new-world&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/old-playdate-new-world.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;more-games&quot;&gt;More games!&lt;/h2&gt;

&lt;p&gt;All my Playdate games:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;YOYOZO&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;read about it being a &lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;GOTY 2023&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/sparrow-solitaire/&quot;&gt;Sparrow Solitaire&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;read the &lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;making of&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/bender-2-bend-harder/&quot;&gt;Bender 2: Bend Harder&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;read the &lt;a href=&quot;/2024/10/08/bender-2-bend-harder-for-playdate/&quot;&gt;making of&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;Fore! Track&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;read the &lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;making of&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Super ICARUS&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;read about its &lt;a href=&quot;/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/&quot;&gt;dynamic music&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 11 Mar 2025 16:24:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/03/11/old-codes-new-releases-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/03/11/old-codes-new-releases-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Making games on iPhone/iPad using Lua &amp; Love2D</title>
          <description>&lt;p&gt;I wondered how feasible it is to make Love2D games “on the go” (on a train, in bed, etc). Often I want to try a quick sketch, work up a prototype, or simply verify an algorithm. I’m happy to say it’s possible!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;runners&quot;&gt;Runners&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Love2D Studio&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Available since Jan 2024&lt;/li&gt;
  &lt;li&gt;Free &lt;a href=&quot;https://apps.apple.com/gb/app/love2d-studio/id6474188075&quot;&gt;apps.apple.com/gb/app/love2d-studio/id6474188075&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;this allows you to manage love files and run them on iPhone&lt;/li&gt;
  &lt;li&gt;Love2D errors can even be copied to the clipboard!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Love2D Game Maker&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Available since March 2024&lt;/li&gt;
  &lt;li&gt;Paid &lt;a href=&quot;https://apps.apple.com/gb/app/love2d-game-maker/id6476174098&quot;&gt;apps.apple.com/gb/app/love2d-game-maker/id6476174098&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;TestFlight &lt;a href=&quot;https://testflight.apple.com/join/bCLmQKfQ&quot;&gt;testflight.apple.com/join/bCLmQKfQ&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;from the creator of LuaLu (see below)&lt;/li&gt;
  &lt;li&gt;comes bundled with a handful of demo games&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.iamadman.com/products/love2d-gamemaker/love2d-game-maker-learn-to-create-the-classic-game-of-pong-in-10mins/&quot;&gt;Pong tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;editors&quot;&gt;Editors&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Textastic&lt;/strong&gt; (since 2010)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Paid &lt;a href=&quot;https://apps.apple.com/gb/app/textastic-code-editor/id1049254261&quot;&gt;apps.apple.com/gb/app/textastic-code-editor/id1049254261&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;text editor with autocomplete and function picker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kodex&lt;/strong&gt; (since 2017)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Free &lt;a href=&quot;https://apps.apple.com/gb/app/kodex/id1038574481&quot;&gt;apps.apple.com/gb/app/kodex/id1038574481&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;text editor with minimap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GoCoEdit&lt;/strong&gt; (since 2016)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Paid &lt;a href=&quot;https://apps.apple.com/gb/app/gocoedit-code-text-editor/id869346854&quot;&gt;apps.apple.com/gb/app/gocoedit-code-text-editor/id869346854&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;text editor with autocomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Runestone&lt;/strong&gt; (since 2022)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Free, limited &lt;a href=&quot;https://apps.apple.com/gb/app/runestone-text-editor/id1548193893&quot;&gt;apps.apple.com/gb/app/runestone-text-editor/id1548193893&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;text editor with clean user interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lua IDE&lt;/strong&gt; (since Feb 2021)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Free &lt;a href=&quot;https://apps.apple.com/gb/app/lua-ide/id1549382090&quot;&gt;apps.apple.com/gb/app/lua-ide/id1549382090&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;this app provides QuickLook support for Lua files&lt;/li&gt;
  &lt;li&gt;at some point you’ll need to check the contents of a Lua file in Files app&lt;/li&gt;
  &lt;li&gt;it also features the full Lua docs (though I use a self-built version of Dash doc viewer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;LuaLu&lt;/strong&gt; (since Apr 2013)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Free &lt;a href=&quot;https://apps.apple.com/gb/app/lualu-repl-learn-lua-coding/id638219114&quot;&gt;apps.apple.com/gb/app/lualu-repl-learn-lua-coding/id638219114&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;sometimes you just need a Lua &lt;a href=&quot;https://en.wikipedia.org/wiki/Read–eval–print_loop&quot;&gt;REPL&lt;/a&gt; prompt to figure out a formula or do a quick experiment&lt;/li&gt;
  &lt;li&gt;features solid debugging support&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;other-lua-ide&quot;&gt;Other Lua IDE&lt;/h2&gt;

&lt;p&gt;If you’re into Lua but not into Love2D then you might try &lt;a href=&quot;https://codea.io&quot;&gt;Codea for iPad&lt;/a&gt;.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 20 Feb 2025 07:37:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/02/20/making-games-on-iphone-ipad-using-lua-and-love2d/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/02/20/making-games-on-iphone-ipad-using-lua-and-love2d/</guid>
        </item>
      
    
      
        <item>
          <title>DREAM RIDE for Sega Dreamcast (and emulators)</title>
          <description>&lt;p&gt;Over the Christmas break I had a spare week after a trip to Ireland was cancelled. What should I do with the time? I was already aware of the upcoming &lt;a href=&quot;https://itch.io/jam/dream-disc-24&quot;&gt;DreamDisc ‘24 game jam&lt;/a&gt; and had done some reading &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1843024068930658594&quot;&gt;a couple of months back&lt;/a&gt; scoping out a Lua-based SDK called ANTIRUINS Engine that looked familiar enough to me with my experience of LÖVE (love2d) and Playdate SDK. But what should I make with it?&lt;/p&gt;

&lt;p&gt;If I could get something fun up and running as quickly as possible it would prove the point and keep me motivated. Sounds like a plan. Also, it’s easier to make something that has already been planned out, so all the effort goes on implementation rather than design. I remembered my unreleased game &lt;a href=&quot;/tag/dailydriver/&quot;&gt;Daily Driver&lt;/a&gt;…maybe I could get those little cars moving around the screen? But what would make it &lt;em&gt;more Dreamcast?&lt;/em&gt; Simultaneous 4-player action and CPU opponents! &lt;em&gt;OK, let’s do this!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It took a bit of effort to get the build process setup, but after that I hit the ground running. I got the physics and 4-player control working pretty quickly. Then the sprites went in, albeit in the wrong colours. Physics equation and sprites are the only two things shared with &lt;a href=&quot;/tag/dailydriver/&quot;&gt;Daily Driver&lt;/a&gt;. Next I added a variety of game modes, power-ups, new sounds, all within a few days. Then I picked at it over the next week to polish it as much as possible before the game jam deadline. I thrive on deadlines.&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a href=&quot;https://bertholet.itch.io&quot;&gt;Bertholet&lt;/a&gt;, author of ANTIRUINS Engine, who has done a great job and was very gracious with his time helping me through the initial hurdles.&lt;/p&gt;

&lt;p&gt;I’ll do a full post-mortem and “what’s next” after the game jam results are announced. But I’m really happy with how it turned out. The cars look great in colour, and even with 8 of them on screen things are a rock solid 60fps, I really need to see how far I can push things.&lt;/p&gt;

&lt;hr /&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/dream-ride-game.png&quot; alt=&quot;IMG&quot; title=&quot;This shows a secret mode where the cars roaming around the menu screen remain in play!&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;download&quot;&gt;Download&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/dream-ride&quot;&gt;gingerbeardman.itch.io/dream-ride&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Play DREAM RIDE on real hardware (tested on my original imported NTSC-U Sega Dreamcast from 1999, &lt;a href=&quot;/2020/12/03/dreamcast-gdemu-installation/&quot;&gt;fitted with a GDEMU&lt;/a&gt;) or in an emulator on your favourite console or handheld (tested with Flycast on macOS, GameForce Chi, Powkiddy RGB30, &lt;a href=&quot;https://twitter.com/0_game_it/status/1875734954946285610&quot;&gt;TrimUI Brick&lt;/a&gt;, and a modded Nintendo Switch).&lt;/p&gt;

&lt;p&gt;Future versions of the game with improvements and new modes will require payment, after all I’m a full-time indie developer and my caffeine intake needs to be maintained. Thanks for your support!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;

&lt;p&gt;Below is a video where I forgot to switch audio source so it recorded audio through my Mac’s mic. 😅&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;movAjOjZLRg&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 05 Jan 2025 23:59:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2025/01/05/dream-ride-for-sega-dreamcast-and-emulators/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2025/01/05/dream-ride-for-sega-dreamcast-and-emulators/</guid>
        </item>
      
    
      
        <item>
          <title>Bender 2: Bend Harder for Playdate</title>
          <description>&lt;p&gt;Back in 2012 I wanted to make a quick game for the &lt;a href=&quot;https://twitter.com/agbicjam&quot;&gt;AGBIC&lt;/a&gt; game jam (A Game By Its Cover; make a game inspired by the imaginary cover art from the &lt;a href=&quot;http://famicase.com&quot;&gt;Famicase&lt;/a&gt; exhibition). There’s only one rule for this game jam, which is taken very seriously: &lt;em&gt;respect the wishes of the original artists, and don’t appropriate their designs without consent&lt;/em&gt;. Otherwise you’re free to do what you want. And you can choose a cover as inspiration for your game from the entire archive of Famicase entries, so every year there are more and more great covers to be inspired by.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2012&quot;&gt;2012&lt;/h2&gt;

&lt;p&gt;I had a browse of the Famicase entries and picked artwork titled &lt;a href=&quot;https://famicase.com/11/softs/12.html&quot;&gt;Bender&lt;/a&gt;, by 清水昭利 Akitoshi Shimizu, from the 2011 submissions, and set to work… thinking. One morning I had the crazy idea to &lt;a href=&quot;/2024/09/28/a-haze-of-inspiration/&quot;&gt;impose severe constraints to help my ideation&lt;/a&gt;: I should make the game using only CSS transitions (and some simple JavaScript logic to control the game state and flow). I have no idea why this seemed like a good idea, but it worked!&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bender-2-famicase-2011.jpg&quot; alt=&quot;IMG&quot; title=&quot;Bender Famicase by Akitoshi Shimizu, 2011&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The result of &lt;a href=&quot;https://twitter.com/gingerbeardman/status/227040932028108800&quot;&gt;two days work&lt;/a&gt; was a web game called Bender released 12th July 2012. It was fun to make and devilishly addictive. The &lt;a href=&quot;https://www.gingerbeardman.com/bender/&quot;&gt;web game&lt;/a&gt; still works today, on desktop and mobile, though the controls are prone to getting stuck from time to time for reasons I’ve not looked into.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.gingerbeardman.com/bender/&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bender-2-web-2012.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2022&quot;&gt;2022&lt;/h2&gt;

&lt;p&gt;Fast forward 10 years and I decided to do a pretty straight port of the web game to the &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; handheld, that was 20th May 2022. I coded it from memory/feel, just for kicks, not that I had any choice as the available technologies are so different. It was a very bare bones game, with no music and messy code, but it was a test to see if I could release a game in a day. I did.&lt;/p&gt;

&lt;p&gt;Seeing as original Bender web game used CSS for all graphics and animation, and a little JavaScript to control the game flow, I had wondered how I would build Bender with the Playdate SDK? I settled on using only primitives and dither patterns to draw all the elements, an approach that I have continued to refine in subsequent games such as my &lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;GOTY 2023 accolade&lt;/a&gt; and &lt;a href=&quot;https://play.date/games/community-awards-2023-arcade/&quot;&gt;award winner&lt;/a&gt; &lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;YOYOZO&lt;/a&gt;, the detailed rendered look of &lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Fore! Track&lt;/a&gt;, or the stark minimalism of &lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Super ICARUS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each side of the bar is a thick line, with “butt” cap-style. To give the illusion of the bar bending I draw a circle at the origin or common point of both lines. A little bit of trigonometry was all that was needed to get the lines bending correctly. The benefits to this approach are many, such as: no images, no sprites, always smooth edges, better performance. Animation also does not use the Playdate SDK, but rather I track the positions of screen elements and move them based on some rules and algorithms.&lt;/p&gt;

&lt;p&gt;I use dithering to provide visual effects: animation of snapping and motion blur of the moving line. There’s also a zen mode that disables visual effects and the toasting words (which are randomised from large lists).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bender-2-playdate-2022.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2023&quot;&gt;2023&lt;/h2&gt;

&lt;p&gt;I submitted Bender for consideration for &lt;a href=&quot;https://play.date/games/catalog/&quot;&gt;Playdate Catalog&lt;/a&gt; when the service launched, but it was rejected for being “too simple”. After some lengthy contemplation my takeaway from the rejection was that it meant there was not enough meat on the bones of the game, rather than anything specific against the central gameplay mechanic which is beautifully simple.&lt;/p&gt;

&lt;p&gt;Fair point. Though I did say I would expand the game, add music and so on, I learned that it’s difficult for people to imagine how you’re going to expand on a simple concept. You need to show them. It took many months—about a year and a half—for me to find the time and energy to revisit Bender.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2024&quot;&gt;2024&lt;/h2&gt;

&lt;p&gt;The end result is &lt;em&gt;Bender 2: Bend Harder&lt;/em&gt;. The new game has been remade, from scratch, right down to the fonts. And it’s packed with new things: friendlier gameplay, more obvious goals, multiple game modes, a deeper scoring system, awards/achievements, multiple secrets/easter eggs, online score boards, improved graphics, dynamic music and sound including elements that react to the beat of the music, an imaginary scenario to provide a bit of world-building, and much more besides! At ~2000 lines the source code is over 4 times the length of the first version’s ~500 lines, just to give you an idea of how much more logic there is in the new game. Not that lines of code is a good metric, but you get my point. There is much new!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There are elements to the game that I would usually disclose the technical details of—my process, tooling—but I’m currently doing my utmost to protect my “vibe” so that won’t happen today. This is why we can’t have nice things. Maybe at some point in the future, but no promises.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyway, I’m really happy how this game has turned out. Can’t wait to see some activity on the leaderboards! Get it at &lt;a href=&quot;https://play.date/games/bender-2-bend-harder/&quot;&gt;play.date/games/bender-2-bend-harder/&lt;/a&gt; and I’ll see you in the high scores!&lt;/p&gt;

&lt;p&gt;As usual, promo artwork is by &lt;a href=&quot;https://www.instagram.com/vxclhd/&quot;&gt;vxcl&lt;/a&gt; with 1-bit equivalents drawn by me.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“If at first you don’t succeed, try, try again.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bender-2-bend-harder.gif#playdate&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;my-other-games-for-playdate&quot;&gt;My other games for Playdate&lt;/h2&gt;

&lt;p&gt;This brings my total of games on Playdate Catalog to 5, the others being:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;YOYOZO&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Best Games of 2023 (Ars Technica)&lt;/li&gt;
      &lt;li&gt;Best Arcade Game (Playdate Community Awards 2023)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;Sparrow Solitaire&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Best Puzzle Game (Playdate Community Awards 2023)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Fore! Track&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;the first &lt;a href=&quot;/2023/07/09/the-first-colour-playdate-game/&quot;&gt;colour&lt;/a&gt; Playdate game?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Super ICARUS&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;an innovative hybrid survival-racing game&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also have a bunch of other games at &lt;a href=&quot;https://gingerbeardman.itch.io&quot;&gt;gingerbeardman.itch.io&lt;/a&gt; for both Playdate and Mac/Windows.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 08 Oct 2024 17:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/10/08/bender-2-bend-harder-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/10/08/bender-2-bend-harder-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>A haze of inspiration</title>
          <description>&lt;p&gt;A long time ago in a galaxy far, far away I had to give an impromptu presentation about something I didn’t know much about. The goal of the task was to see how well we could ad-lib a presentation under pressure. Everybody in the room had to think of a topic whilst waiting for our turn. The person next to me couldn’t think of anything and asked me what I had thought of, I said “the off-side rule” (it’s a football/soccer thing, don’t worry about it). Then that person was called before me and proceeded to give a presentation about… the off-side rule. I was mortified, and when my turn came I was still so shell shocked that I can’t remember what other topic I picked was, or even how the rest of the day went. Afterwards I chatted with the person—at the time we were good friends and continue to be to this day—who told me when their name was called “a haze of inspiration” came over them and the only thing they could think about was the topic I’d just mentioned. And so it was.&lt;/p&gt;

&lt;hr /&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/haze-of-inspiration.webp&quot; alt=&quot;WEBP&quot; title=&quot;“boat sailing in body of water”, photograph by Joel Bengs (courtesy of &amp;lt;a href=&amp;quot;https://unsplash.com/photos/boat-sailing-in-body-of-water-arYiUpN5tZk&amp;quot;&amp;gt;Unsplash&amp;lt;/a&amp;gt;)&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;from-whence-it-came&quot;&gt;From whence it came&lt;/h2&gt;

&lt;p&gt;Just as a haze obscures clear vision, the creative process can blur the lines between our own ideas and those we’ve encountered. We can be inspired by everything around us, in an unconscious way. I’d venture to say that this is the most common form of inspiration, you’re just existing and soaking up as much as you can. In some ways it is automatic and unavoidable. As a result, we share a lot of common experiences and so this sort of natural inspiration can lead to the Zeitgeist, with similar ideas emerging simultaneously in different places. A sort of opposite to this is the concept of incremental innovation, where small changes happen to existing ideas that are occasionally enough for it to feel new. And then there are the types of new ideas that can’t be easily found elsewhere, that are provably innovative and totally new. By definition the haze of inspiration is a very grey space, difficult to navigate, and open to interpretation. There’s no absolute right or wrong, unless you are in a position to flex legal muscles. Below is my own interpretation of how I see things, it’s expected that you won’t agree with all of it.&lt;/p&gt;

&lt;h2 id=&quot;navigating-the-haze&quot;&gt;Navigating the haze&lt;/h2&gt;

&lt;p&gt;I often pause and examine my own creative process. This serves a number of purposes: it helps me notice opportunities for improvement that might otherwise be missed along the way. If my head is down, I might not notice that I can save time by refining my workflow, or gain new understanding by looking at a problem from a different angle or through a different lens.&lt;/p&gt;

&lt;p&gt;Tracking or keeping a record of things you find inspiring is very useful. Some might use Pinterest, bookmark managers, scrap books, print outs, notebooks, folders of saved files. Whatever works for you, really.&lt;/p&gt;

&lt;p&gt;At this point I feel it’s worth mentioning the challenge of distinguishing between inspiration and imitation. We can all be inspired by something, but how we choose to act on the inspiration can be a challenge. How much you take away from the inspiration might mean you cross the line into imitation. The difference between the two is open to interpretation, and legally it’s a very grey area, so it requires understanding of our own moral compass. More on that later. But for me the difference can be summarised by how comfortable I am in the knowledge that I put enough of myself into the idea, then I’m inspired. If I don’t put enough of myself into the idea, then I would call it imitation.&lt;/p&gt;

&lt;h2 id=&quot;original-thinking&quot;&gt;Original thinking&lt;/h2&gt;

&lt;p&gt;Thinking can be difficult, and coming up with original thoughts is even more difficult. One could ask if it’s even possible at all to have an original thought? I think it is, though it’s often said that “&lt;a href=&quot;https://www.youtube.com/watch%3Fv%3DX9RYuvPCQUA&quot;&gt;everything is a remix&lt;/a&gt;”. My personal feeling is that an original thoughts can only come when you take yourself out of the equation. Famous artists used drugs, alcohol, and more. Karl Wallinger of the band World Party (check out the album “Goodbye Jumbo”) famously “&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/darko-audio-podcast/id1368388920?i=1000514052892&quot;&gt;never worked straight&lt;/a&gt;” (~25:30), he would always smoke a joint with the idea being “to get yourself out the fucking way”. John Lennon, too, though perhaps with harder stuff.&lt;/p&gt;

&lt;p&gt;On the other hand Quincy Jones used a technique where he would get himself into what he called “&lt;a href=&quot;https://www.clashmusic.com/features/in-conversation-questlove/&quot;&gt;the alpha state&lt;/a&gt;”, a kind of liminal space between being asleep and awake, where he would routinely have all of his best ideas. Miles Davis used &lt;a href=&quot;https://coppice-gate.com/film/402/miles-davis-the-first-improvised-music-film-soundtrack&quot;&gt;improvisation&lt;/a&gt;. Salvador Dalí used a technique he called “&lt;a href=&quot;https://mma.pages.tufts.edu/fah188/clifford/Subsections/Paranoid%20Critical/paranoidcriticalmethod.html&quot;&gt;paranoiac-critical method&lt;/a&gt;” to access his subconscious through fear. David Lynch uses &lt;a href=&quot;https://www.vice.com/en/article/david-lynch-wants-you-to-meditate-maybe-make-a-lamp-during-self-isolation/&quot;&gt;meditation&lt;/a&gt;. Brian Eno used a deck of cards called “&lt;a href=&quot;https://en.wikipedia.org/wiki/Oblique_Strategies&quot;&gt;Oblique Strategies&lt;/a&gt;” to add constraints to the creative process. David Bowie used a “&lt;a href=&quot;https://en.wikipedia.org/wiki/Cut-up_technique&quot;&gt;cut-up technique&lt;/a&gt;” (also called découpé), adapted from one used by William S. Burroughs but with much older origins, where existing works were cut up and rearranged into new works. My current favourite pop star, Lo Lauren, &lt;a href=&quot;https://www.youtube.com/watch?v=infNIRbESVE&amp;amp;list=PLCu6QvIFB9Chc-pTB0tWnUv67ufwVz8zO&amp;amp;pp=iAQB&quot;&gt;creates songs in 10 minutes&lt;/a&gt; over a found beat using three suggested words to focus the topic of the lyrics. It’s encouraging to realise that there is more than one method and that you can most likely find one that works for you.&lt;/p&gt;

&lt;p&gt;My own method is to recede into the haze itself, into darkness. The simple act of laying down in a quiet room, and closing my eyes for a few minutes is usually enough for me to navigate through the haze and come out with an original idea, solution to a problem, name of a new product, or whatever.&lt;/p&gt;

&lt;h2 id=&quot;research&quot;&gt;Research&lt;/h2&gt;

&lt;p&gt;For me, outside of the actual act of creation, this is most fun part of the creative endeavour. The world is literally your oyster. Given that 99% of stuff happened in the past, I prefer to consult historic sources. Old magazines, books, interviews, and of course the video games and music I grew up with are now old enough to qualify. Ha! The most important thing here is to look outside your field of view. It’s easy to be inspired by the things right in front of you, but more difficult—and more rewarding—to be inspired by things further afield. Reach deeper, go further, get outside your comfort zone, take the road less travelled.&lt;/p&gt;

&lt;p&gt;Once inspired, or locked on to an idea, it’s important to do some due diligence to check that it’s unique, or not protected by any laws or copyright, or even just to check that a name is free enough to be used. Domain names can be taken, hashtags can be already used. My funniest example is when I was originally calling my hit game &lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;YOYOZO&lt;/a&gt; by another name: YOYOZORA, which is a combination of the words YOYO (the toy) and YOZORA (the Japanese word for night sky). I quickly changed plans when a hashtag search revealed somebody posting dick pics.&lt;/p&gt;

&lt;p&gt;It’s worth noting that some creators intentionally avoid external influences during their creative process, believing this leads to more original work. Nick Cave, for instance, &lt;a href=&quot;https://the-talks.com/interview/nick-cave/&quot;&gt;avoids listening to music while writing&lt;/a&gt; to prevent unconscious imitation. Filmmaker Jim Jarmusch tries not to watch other films, or &lt;a href=&quot;https://cinemontage.org/stranger-than-paradox-jim-jarmusch/&quot;&gt;even the scenes he has already shot&lt;/a&gt;, while working on a project to maintain his unique vision. Even in tech, Steve Jobs was known for his “&lt;a href=&quot;http://www.stephengobeli.com/analysis/not-invented-here/&quot;&gt;not invented here&lt;/a&gt;” syndrome, often preferring to develop ideas from scratch. This approach isn’t about ignoring the world entirely, but about creating a space where your own ideas can flourish without immediate external influence. It’s a delicate balance – you want to be informed, but not overly swayed by what’s already out there.&lt;/p&gt;

&lt;h2 id=&quot;attribution&quot;&gt;Attribution&lt;/h2&gt;

&lt;p&gt;By now you’ll know in your heart if what you’re dealing with is imitation or inspiration. What next? Methods of attribution might include: direct credit, “inspired by”, footnotes, a mention, etc. Or if the inspiration is barely visible at all there might be no attribution needed. There’s that moral compass again.&lt;/p&gt;

&lt;p&gt;Attribution can add value to your work, as it shows not only are you compassionate and considerate, but that you value the creativity of other people. In some fields, like music and visual arts it’s perhaps more difficult to do some forms of attribution. You can’t put a list of credits on a painting or in an audio recording, but you can put them in supporting material. There’s always a way.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I won’t spend much time on the topic of “AI”, or to be more precise “generative tools”, but it’s worth mentioning them briefly at this point as they lack any method of attribution which of course is a problem. How big a problem depends on how much originality is in the result and that is a very difficult thing to measure, though I would say not impossible at least regarding the series of prompts that led to the output. Anyway, the results from the use of such tools is also open to interpretation and perhaps this is even more of a grey area than the haze of inspiration itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;communication&quot;&gt;Communication&lt;/h2&gt;

&lt;p&gt;So how do you figure out how best to attribute? By reaching out and having a conversation. But that’s easier said than done, I think.&lt;/p&gt;

&lt;p&gt;I’ve never gone so far as to write a formal letter or anything like that, I’ve been more casual about it. I’ve written to game developers whose games I wanted to port. Having something for them to see is always good—a prototype—and explaining the expectations and reach of the agreement will make everybody feel comfortable. There will surely be some anxiety and reticence for an idea to be taken by somebody else. In my experience I try to frame it in as positive a way as possible. Answer the questions they might have before they even have a chance to think them.&lt;/p&gt;

&lt;p&gt;Timing is always key. I always make such an approach as soon as possible. With my game &lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Fore! Track&lt;/a&gt;, I contacted the developer whose game I was inspired by as soon as I had a prototype up and running. At that point, if they’d have objected to the idea I wouldn’t have lost much time. If I’d have contacted them with a finished game, it might not have made much difference to their decision making process, but I would have had more invested in it and more to lose. Contacting somebody with only an idea for me feels like the wrong way to go about it, as &lt;a href=&quot;https://sive.rs/multiply&quot;&gt;ideas are relatively easy and execution is everything&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With such discussions it’s important to have open conversations, which will can lead to mutual understanding and respect. Leave your ego at the door and bring truthfulness, compassion, open-mindedness and you will be rewarded. Misunderstandings will inevitably happen through the course of the conversation, but by being open both parties can rest assured that there will only be movement towards resolution rather than escalation.&lt;/p&gt;

&lt;p&gt;By far the best outcome of such open discussions is the fact that two heads are better than one so the solution is almost always better than the original idea or approach. This means it’s in your own interests to have these sorts of conversations as often as possible. They might lead to better ideas, collaboration, partnerships, refinement, suggestions you would never have thought of, about turns, and of course rejection.&lt;/p&gt;

&lt;p&gt;Rejections are always hard to take, but I’m a firm believer that with time, and enough water under the bridge, that newer and stronger ideas will emerge. For me that can take weeks, months, even years. But every time it happens I think “the Universe provides” and smile.&lt;/p&gt;

&lt;h2 id=&quot;ethical-considerations&quot;&gt;Ethical considerations&lt;/h2&gt;

&lt;p&gt;So, about that moral compass I keep mentioning. Ideas are more than a feeling, especially when executed and turned into something that can be seen, heard, played. They turn from intangible to tangible, and this process is guided by your moral compass.&lt;/p&gt;

&lt;p&gt;When it comes to that “haze of inspiration”, intellectual integrity is the needle on your moral compass. It helps you navigate through the fog without stepping on anyone’s toes. It’s about asking yourself not whether you could use an idea, but whether you should. It’s about being upfront about what inspired you, maybe asking for a thumbs-up if you’re borrowing heavily from someone else’s work, and generally just being a decent human in the creative playground. By sticking to these principles, you’re not just keeping your own nose clean. You’re helping to create an environment where ideas can bounce around freely, where people aren’t afraid to share their cool thoughts, and where everyone gets their due credit. It’s like keeping the idea ecosystem healthy, you know?&lt;/p&gt;

&lt;p&gt;Intellectual integrity is really just about not being a jerk with other people’s ideas. It’s about giving credit where it’s due, trying to get your facts straight, and not twisting things to fit your narrative. It’s also about owning your work, warts and all. If you messed up or your info isn’t 100% solid, just say so. Nobody’s perfect, right? And here’s an important addition: be open to other viewpoints. Just because someone disagrees with you doesn’t mean they’re wrong (even if you really, really think they are).&lt;/p&gt;

&lt;p&gt;All ideas build on previous work. I subscribe to the idea that everything is a remix, and I also know that being cool, kind, and considerate costs nothing. Being uncool, unkind, or inconsiderate can cost you more energy in the long run. Time teaches that particular lesson, so consider it being mentioned here a free power-up. We are lucky enough to be able to stand on the shoulders of giants, so it’s important to not make a mess whilst we’re up there.&lt;/p&gt;

&lt;h2 id=&quot;personal-growth&quot;&gt;Personal growth&lt;/h2&gt;

&lt;p&gt;Growing is hard and with it come a lot of pains. Road blocks, wrong turns, bad luck, but hopefully it will trend towards progress.&lt;/p&gt;

&lt;p&gt;One key aspect of growth is synthesis. Plants turn light energy into chemical energy through photosynthesis. The output is vastly different to the input. I think this is a useful lens through which to look at techniques for turning influences into something truly novel. You can look at the &lt;a href=&quot;/2023/04/10/where-can-i-see-hokusai-great-wave-today/&quot;&gt;The Great Wave&lt;/a&gt; and print your own version of it if the goal is to imitate it as closely as possible (as &lt;a href=&quot;https://www.youtube.com/playlist?list=PLK-Wicsj5rAasS2g7e-Z9eFUdG6I7ZqED&quot;&gt;David Bull&lt;/a&gt; has done), or you might choose to draw it instead and replace the crests of the wave with bunny rabbits (as &lt;a href=&quot;https://shop.kozyndan.com/products/uprisings-poster&quot;&gt;kozyndan&lt;/a&gt; did), or you might sculpt it from digital clay and add some mahjong tiles to it (like &lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;vxcl did for my game Sparrow Solitaire&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I like to think of this synthesis as a road—you can turn off at any point but the further you go the more wonderful the sights will be. I’d like to make a short detour to mention constraints and how they can foster creativity. Whilst the road might be long, it’s not sprawling but a single direction. Navigating a complex road system would be much more difficult, so I encourage you to impose additional constraints if there don’t seem to be enough, or if the way forward isn’t clear.&lt;/p&gt;

&lt;p&gt;Any period of not creating that you end up in is just as important as a period of intense creativity that you might rather be in. My favourite quote about this (by BT, the musician; I’m paraphrasing) is that creativity comes in waves, sometimes you’re in the doldrums and not much is happening but there is no doubt that the next wave will arrive at some point, so you just have to be ready to jump on and ride it when it does!&lt;/p&gt;

&lt;p&gt;It’s a fine balance between being influenced and being derivative. Sadly your moral compass is not fitted with a warning alarm of any sort, so you’ll have to rely on your heart, head, and those of others to give you guidance here. Having respect for others’ ideas can be considered a constraint in and of itself and can actually push you to be more innovative. Being derivative is a trap to be avoided, not only would you not gain as much personally from the endeavour but you might also inadvertently dilute the idea, brand, vibe of the originator. You should instead consider the person who has inspired you as a mentor, supporter, team mate, power-up, voice of reason, or even shoulder to cry on. The important take-away is that they are there to help because, hey, they were there first.&lt;/p&gt;

&lt;h2 id=&quot;embracing-the-future&quot;&gt;Embracing the future&lt;/h2&gt;

&lt;p&gt;With enough searching, or metaphorical travelling, you’ll be able to find your own voice, style, brand, or “vibe” as I prefer to call it. I’m a bit of a hippie at heart. The ultimate goal is to find that rug that really ties the room together. Then cherish it, feed it, sculpt it, even defend it if the need arises. You’ll have the ideas, make a &lt;a href=&quot;https://allaboutstevejobs.com/verbatim/interviews/playboy_1985&quot;&gt;dent in the universe&lt;/a&gt;, and develop a vibe that other people will be influenced by, and hopefully they will take the right path and be inspired by it rather than choose to imitate it. Perhaps that’s the ultimate goal? It’s your turn to set a good example for those that come after you.&lt;/p&gt;

&lt;hr /&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;j29Vjxi_oAg&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;center&gt;Excerpt from &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Big_Lebowski&quot;&gt;The Big Lebowski&lt;/a&gt; (Ethan &amp;amp; Joel Coen, 1998)&lt;/center&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/60965426-the-creative-act&quot;&gt;The Creative Act: A Way of Being&lt;/a&gt; (Rick Rubin, 2023)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/13099738-steal-like-an-artist&quot;&gt;Steal Like An Artist&lt;/a&gt; (Austin Kleon, 2021)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/10770576-the-ecstasy-of-influence&quot;&gt;The Ecstasy of Influence&lt;/a&gt; (Jonathan Lethem, 2011)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sive.rs/multiply&quot;&gt;Ideas Are Just a Multiplier of Execution&lt;/a&gt; (Derek Sivers, 2005)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/8083765-think-like-da-vinci&quot;&gt;Think Like Da Vinci&lt;/a&gt; (Michael J. Gelb, 1998)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/18144590-the-alchemist&quot;&gt;The Alchemist&lt;/a&gt; (Paulo Coelho, 1988)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/20425787-oblique-strategies&quot;&gt;Oblique Strategies&lt;/a&gt; (Brian Eno &amp;amp; Peter Schmidt, 1975–2001)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/780304.Design_Methods&quot;&gt;Design Methods&lt;/a&gt; (John Chris Jones, 1970–1992)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.hermanmiller.com/stories/why-magazine/design-q-and-a-charles-and-ray-eames/&quot;&gt;Design Q &amp;amp; A&lt;/a&gt; (Charles &amp;amp; Ray Eames, 1969–1972)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/157993.The_Little_Prince&quot;&gt;The Little Prince&lt;/a&gt; (Antoine de Saint-Exupéry, 1943)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks to vivarado for feedback on this piece ahead of publication.&lt;br /&gt;
And to Nick, Charlie, Jan and Neil for feedback that led to later revisions.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 28 Sep 2024 17:46:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/09/28/a-haze-of-inspiration/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/09/28/a-haze-of-inspiration/</guid>
        </item>
      
    
      
        <item>
          <title>This behavior is by design</title>
          <description>&lt;p&gt;Back in the mid-1990s I was using Windows 95/98 and running up against bugs, problems, driver issues, unexpected things happening. I would often end up on the Microsoft Knowledge Base support web pages, where the issue would often be accompanied by the line “&lt;a href=&quot;https://support.microsoft.com/en-gb/topic/you-can-change-the-desktop-wallpaper-setting-after-administrator-selects-prevent-changing-wallpaper-option-in-group-policy-e3af8a03-69f5-e320-42dc-15702ba5375c&quot;&gt;This behavior is by design&lt;/a&gt;”, which remains in use to this very day.&lt;/p&gt;

&lt;p&gt;This mantra has stuck with me over the years, and it came to light in a recent discussion about the design of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lucas_Pope&quot;&gt;Lucas Pope&lt;/a&gt;’s &lt;a href=&quot;https://play.date/games/mars-after-midnight/&quot;&gt;Mars After Midnight&lt;/a&gt; for the &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; handheld game console. It has a black interstitial screen between some scenes, which was enough to get me thinking about the intent behind the design of a screen that contains …nothing at all.&lt;/p&gt;

&lt;h2 id=&quot;to-be-or-not-to-be&quot;&gt;To be or not to be&lt;/h2&gt;

&lt;p&gt;I’m as guilty as anybody in wondering why certain things are how they are in the software, apps, or games I’m using. It’s a fundamental truth about software development that often goes unnoticed by end users: every aspect of computer software is the result of deliberate human decisions, from the broadest feature sets right down to the placement of individual pixels.&lt;/p&gt;

&lt;p&gt;This intentionality in software design has profound implications. It means that the user experience—whether frustrating or delightful—stems from choices made by developers, designers, product managers, and perhaps even the users themselves. How enjoyable or not the software is to use, the accessibility (or lack thereof) of user interfaces, and even the bugs and glitches we encounter are all products of the human decision-making process. This perspective challenges the notion that technology is impersonal, as there are human minds and motivations behind every aspect.&lt;/p&gt;

&lt;p&gt;However, it’s worth noting that while every element is designed, not all design decisions are made with equal deliberation or foresight. Some choices are carefully considered and tested, while others might be rushed, overlooked, or based on flawed assumptions. Additionally, the complexity of modern software means that interactions between different design choices can sometimes lead to unintended consequences. More on that later.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;/h2&gt;

&lt;p&gt;Given that we could go on forever with examples, here are 10 off the top of my head:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;whether or not there’s a black screen between scenes in a game&lt;/li&gt;
  &lt;li&gt;size of padding or border around the edge of a dialog box&lt;/li&gt;
  &lt;li&gt;radius of a rounded rectangle&lt;/li&gt;
  &lt;li&gt;spacing or kerning between specific letters of a font&lt;/li&gt;
  &lt;li&gt;aliasing or anti-aliasing around the edge of a circle&lt;/li&gt;
  &lt;li&gt;speed at which an object moves across the screen&lt;/li&gt;
  &lt;li&gt;what happens when you press a button or do an action&lt;/li&gt;
  &lt;li&gt;wording on a menu item or dialog box&lt;/li&gt;
  &lt;li&gt;order of two competing buttons that mean cancel or proceed&lt;/li&gt;
  &lt;li&gt;the number of digits used to represent a high score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Making a game involves deciding on thousands upon thousands of tiny things like this. I love it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;happy-accidents&quot;&gt;Happy accidents&lt;/h2&gt;

&lt;p&gt;While most aspects of software are meticulously planned, sometimes unintended behaviors or glitches lead to serendipitous discoveries. These “happy accidents” might result in a breakthrough in design and can become beloved features if developers choose to keep them.&lt;/p&gt;

&lt;p&gt;A famous example is the “creeper” in Minecraft, which resulted from a coding error while creating pigs. The game’s creator, &lt;a href=&quot;https://en.wikipedia.org/wiki/Markus_Persson&quot;&gt;Markus Persson&lt;/a&gt;, liked the mistaken entity so much that he decided to keep and refine it, turning it into one of the game’s most iconic elements. Similarly, the &lt;a href=&quot;https://www.ssbwiki.com/Wavedash&quot;&gt;wavedash technique in Super Smash Bros. Melee&lt;/a&gt; was an unintended consequence of the game’s physics engine, but it became a crucial part of high-level play after creator &lt;a href=&quot;https://www.ssbwiki.com/Masahiro_Sakurai&quot;&gt;Masahiro Sakurai&lt;/a&gt; opted to leave it in. These instances remind us that even in a world of intentional design, there’s room for the unexpected—and the human decision to embrace and incorporate these accidents can lead to some of the most innovative and engaging aspects of software.&lt;/p&gt;

&lt;h2 id=&quot;deciding-by-not-deciding&quot;&gt;Deciding by not deciding&lt;/h2&gt;

&lt;p&gt;Some might argue that you don’t make a choice when you accept the default settings, like the white background and font in a Word document. Or you might make the same argument about using an existing framework, package, template, or SDK in your software. However, I would argue that by using the defaults you are implicitly agreeing with the designers’ choices. As a user you become complicit in the design decisions simply by not changing them.&lt;/p&gt;

&lt;p&gt;This tacit agreement with default settings is another aspect of design that often goes unnoticed, yet it plays a significant role in shaping the end product. Somebody at Microsoft decided that with Office 2007 the default font would become Calibri, replacing Times New Roman which had been the default since forever. There’s no better example of the implications and reach of a single human decision.&lt;/p&gt;

&lt;h2 id=&quot;thinking-about-the-future&quot;&gt;Thinking about the future&lt;/h2&gt;

&lt;p&gt;At the end of the day, computers do only what we direct them to do, so every aspect of software has been touched by the hand of a human. With the rise of machine learning and “AI” coding assistants, that human touch may become increasingly abstracted from view. However, rest assured it is still there. Even in systems that utilize artificial intelligence, humans are designing the algorithms, curating and creating the training data, and making decisions about how to implement and apply these tools. The fundamental truth remains: behind every line of code, every pixel, and every feature, there are human decisions shaping our experiences.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 28 Aug 2024 21:46:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/08/28/this-behavior-is-by-design/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/08/28/this-behavior-is-by-design/</guid>
        </item>
      
    
      
        <item>
          <title>Pitching a game based on the CICLOPE 2016 Opening Film</title>
          <description>&lt;p&gt;A little over a year ago I wrote a screenplay/pitch for a video game based on an animated short film created by &lt;a href=&quot;https://www.thelineanimation.com&quot;&gt;THE LINE Animation Studio&lt;/a&gt;: the opening film from the CICLOPE Festival in 2016.&lt;/p&gt;

&lt;p&gt;I’d like to make this game but I need support to do so. Until then I figured I’d post it here for all to read.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;ciclope&quot;&gt;CICLOPE&lt;/h2&gt;

&lt;p&gt;Think of this as the game trailer. Watch it before or after reading.&lt;/p&gt;

&lt;iframe src=&quot;https://player.vimeo.com/video/190700988?h=adadcd17c5&amp;amp;title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;740&quot; height=&quot;310&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; fullscreen; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;More information on the making of the animation at &lt;a href=&quot;https://www.thelineanimation.com/work/ciclope/&quot;&gt;thelineanimation.com/work/ciclope/&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;game-overview&quot;&gt;Game Overview&lt;/h2&gt;

&lt;p&gt;Our task is to transport the package to its destination.&lt;/p&gt;

&lt;p&gt;We start the game not knowing what, why, or how.&lt;/p&gt;

&lt;p&gt;The story would involve the environment and its occupants, across many scenarios. We would work together to overcome problems and allow the drone to complete its journey.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The overarching theme of the game is that we could and should all live in harmony together, make use of what we have around us, treat each other and the Earth with respect, and live a happy life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The experience is not a walking simulator, it is more than that. It is a truly interactive, guided story, with puzzles and multiple paths.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;scenarios&quot;&gt;Scenarios&lt;/h2&gt;

&lt;p&gt;These are the scenarios shown in the film and story boards. I’m giving them names here, but I do not see them being named in the game as it will strive to use as little text as possible.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-01.delta.jpg&quot; alt=&quot;Ciclope-01&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;delta&quot;&gt;Delta&lt;/h3&gt;

&lt;p&gt;We first see the drone flying above an River delta at low tide, arriving from an unknown location. We are immediately tasked with flying the drone, following the strand of river that we are on. The camera angle is locked to point only down. We do not see that we are carrying a package.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;On subsequent play-throughs we would fly low to pick up some “gold dust” on the package we are carrying for a special bonus in the ending sequence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After a while everywhere starts to look the same, every tree looks the same, every bit of riverbed looks the same. The small river we have been following starts to disappear, eventually branching into another which does the same. We realise that we are lost.&lt;/p&gt;

&lt;p&gt;Picking up clues from the environment, we figure out that the best course of action is to follow the direction in which the water is flowing, eventually reaching the open sea.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;River deltas have proven to be important throughout human civilisation, as they are major agricultural and population centres. They could be considered the cradle of civilisation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We cross the open sea only to encounter an electric fence, we have to seek the help of animals to find the hole in the fence and continue our journey. Near the hole in the fence we find a small satellite dish and overhear some broken comms/broadcast that we cannot understand.&lt;/p&gt;

&lt;p&gt;We see our reflection for the first time in the water and see a label stencilled on our housing: D3174 (“Delta”).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: beautiful landscapes, ourselves&lt;/li&gt;
  &lt;li&gt;we feel: found, lost, new beginnings, purpose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-02.opening-credits.jpg&quot; alt=&quot;Ciclope-02&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;opening-credits&quot;&gt;Opening Credits&lt;/h3&gt;

&lt;p&gt;This acts as a tidy segue between river delta and desert, showing star-filled sky and sun-bleached-sky signifying that much time has passed and distance has been covered.&lt;/p&gt;

&lt;p&gt;Here it is revealed for the first time that we are carrying a package.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: the vast expanse, the wide world, stars, sun, endless vistas&lt;/li&gt;
  &lt;li&gt;we feel: excited, inquisitive, small, ill-equipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-03.desert.jpg&quot; alt=&quot;Ciclope-03&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;desert&quot;&gt;Desert&lt;/h3&gt;

&lt;p&gt;After flying through the desert for a while, exploring structures, a sand storm approaches and we are forced to take shelter in a small hut at the base of a felled pylon. Here we are taught first hand how we can drop the package if we need to (but only on places where X marks the spot) and how we can pick up and combine items. We learn how to craft new objects with the things we find around us.&lt;/p&gt;

&lt;p&gt;After the storm has passed (coincidentally as soon as we have completed the tutorial objectives) we are allowed to go back outside. We discover lots of new things: a partially covered megalithic monument where we are able to find a replacement battery, and a satellite dish and broadcasting station.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Similar partially covered monuments are visible in all locations, and are a reference to technology and discoveries that have been forgotten in the name of progress.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need to use our new crafting ability to reconnect the equipment. We then receive our first communication/broadcast. But what form does it take?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One idea would be for it to be famous radio broadcasts in foreign languages, celebratiing technological breakthroughs related to the current scenario. eg. the desert could be Africa, and the radio broadcast could be about, say, CT scan etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are also given our first new ability, an Augmented Reality (AR) overlay on our camera view allowing us to see certain invisible things in the environment such as hot air drafts.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: sand storm, crafting, invisible stuff&lt;/li&gt;
  &lt;li&gt;we feel: accomplished, empowered&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-04.oasis.jpg&quot; alt=&quot;Ciclope-04&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;oasis&quot;&gt;Oasis&lt;/h3&gt;

&lt;p&gt;The transition out of the desert takes the form of an encounter with an oasis.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This gives us the opportunity to have a flash-back or flash-forward, somewhat acid trip sort of interjection in the story. Half through our AR glasses and half through the scene. We see elements of what has happened on Earth to leave the landscape in such a ravaged state. It is not Nuclear war, or AI, but simply a result of our over-use of Earth’s resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are left wondering… what was real and what was imaginary?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: psychedelic, trippy, quick-cut flashes from another time&lt;/li&gt;
  &lt;li&gt;we feel: confused, lost, humbled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-05.solar-farm.jpg&quot; alt=&quot;Ciclope-05&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;solar-farm&quot;&gt;Solar Farm&lt;/h3&gt;

&lt;p&gt;We see something on the horizon, something that looks like a city. Perhaps our experience at the oasis had foreshadowed this? We instinctively head in that direction, and it turns out to be much closer than it looked because it is much less tall than it looked at a distance.&lt;/p&gt;

&lt;p&gt;We have encountered a solar farm, with panels stretching as far as the eye can see in every direction.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In fact the game makes sure it is impossible to fly away from them, see Notes section at the end of this document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After our ordeal in the desert we have a problem with our battery and solar panel.&lt;/p&gt;

&lt;p&gt;We need to figure out where in the solar farm we have to go, maybe there is something here we can use to craft a solution. Racing against daylight and the approaching shadows of nightfall we are forced in a certain direction. We realise we can follow the cables on the ground much like we followed the rivers at the delta. We end up at a hut somewhere in the solar farm.&lt;/p&gt;

&lt;p&gt;We immediately find a new battery, but replacing our solar panel will be more difficult. Another satellite comes online and we receive more comms. We see signs of a power source radar, we have to find it and pick it up. But how?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We need to build a Rube Goldberg-style contraption involving: a fragment of our existing solar panel, the reflection of the sun to concentrate light/heat, the water tower, and of course the drone. The water tower ruptures and water floods onto the land and down a previously unseen drainage system. We fly through the pipes into an underground facility where we find a replacement solar panel and our power source radar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;we see: signs of sustainable technology, signs of an advanced human race&lt;/li&gt;
  &lt;li&gt;we feel: empowered, less small, hopeful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-06.coastline.jpg&quot; alt=&quot;Ciclope-06&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;coastline&quot;&gt;Coastline&lt;/h3&gt;

&lt;p&gt;We see the megalithic monuments for the first time.&lt;/p&gt;

&lt;p&gt;Our radar picks up its first sign of power, but we cannot reach it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We need to fly to top of the tower, in stages as we do not have the power to fly at once. When we get to the top we realise we are low on battery. The only things up there are a rock and a small plank of wood. We have to position the wood on the rock and then land on it like a see saw. The wood then flips over and lands on top of us, interlocking with our frame to create wings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We dive from the top of one monument and glide over to the other monument, to sunlight and safety, and a replacement power source.&lt;/p&gt;

&lt;p&gt;The gliding in this stage is reminiscent of hang-gliding in Pilotwings (SNES, N64, DS) where you need to fly through rings of dots and catch updrafts. These can be see thanks to the item we obtained in the desert.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: strange monuments to lost technology&lt;/li&gt;
  &lt;li&gt;we feel: mysterious, capable, resourceful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-07.cut-scene.jpg&quot; alt=&quot;Ciclope-07&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;cut-scene&quot;&gt;Cut Scene&lt;/h3&gt;

&lt;p&gt;The transition from coastline takes the form of an introduction to our Augmented Reality camera.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We see AR overlays of ravaged landscape showing aspects of how it used to be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-08.volcanic.jpg&quot; alt=&quot;Ciclope-08&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;volcanic&quot;&gt;Volcanic&lt;/h3&gt;

&lt;p&gt;We use two abilities of our AR camera in this tricky scenario. We need to find a path through the steam that avoids heat, and use updrafts to reach difficult heights.&lt;/p&gt;

&lt;p&gt;We reach a set of six communications towers but they are offline. One of the six towers is broken and we need to fix it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We need to find some metal, smelt it in the heat, pick it up when safe to do so, find wire and a way to cut it, and all to fashion a replacement resistor. We also need to find, untie and otherwise free various wires, and eventually re-plug them to get the system powered up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We get the system online and hear more comms.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: heat haze, AR views&lt;/li&gt;
  &lt;li&gt;we feel: relieved, capable, hot!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-09.mountains-valley.jpg&quot; alt=&quot;Ciclope-09&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;mountains-valley&quot;&gt;Mountains: valley&lt;/h3&gt;

&lt;p&gt;We see the broken monorail. In the distance we can hear the sound of cattle bells.&lt;/p&gt;

&lt;p&gt;We pick up a power signal and after some effort removing a rock fall, we enter a tunnel and find a small monorail cart. It’s a close cousin of the drone, for the purposes of delivery and operated by the same company. But it’s much older, from the days before drones.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We have to go through the waterfall to collect the battery. Now we have two options, we can leave the area with the battery we have found, or we can go back to monorail cart and give it the battery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By donating the battery the monorail cart bursts into action and we discover that it is part of a much larger system. The various parts all come to life and start to reconnect the monorail track. This results in a special bonus in the ending sequence.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We are also given a new ability for our kindness: language translation which will allow us to understand the contents of all the broadcasts in the game. These abilities can be kept for New Game+ allowing us to see the contents of the earlier broadcasts which add an extra level of depth to the story line on second playthrough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the task is complete we feel as big as the mountains and capable of anything.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: the bigger picture, traces of other useful technology&lt;/li&gt;
  &lt;li&gt;we feel: huge, helpful, part of something bigger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-10.storm.jpg&quot; alt=&quot;Ciclope-10&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;storm&quot;&gt;Storm&lt;/h3&gt;

&lt;p&gt;This scenario not only shows some fancy weather effects, but also shows us that we can save battery power by switching off our light and by not using our other abilities.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We manage to locate a hole in the electrified fence. Once we fly through the storm abates. We are low on power but pick up a radar signal locating a power source. We fly towards it but our battery is depleted giving us no choice but to crash land. The music has been building all this time, becoming more somber, but now it falls completely silent. We hear the strained whine of motors that do not have enough power.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The image fades to black, and we think it might be game over.&lt;/p&gt;

&lt;p&gt;A short while later the scene comes back and it is day time. We are in the opening of a cliff-side cave. We see ancient murals depicting a peaceful world.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We can photograph these with our AR camera to get a special bonus in the ending sequence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enough sun has entered the cave to recharge our battery enough for us to continue our journey. From our current vantage point we can see we are almost at the peak of a mountain range. The only way is up!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: rain, lightning, the end?&lt;/li&gt;
  &lt;li&gt;we feel: relieved, born again, recharged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-11.mountains-peak.jpg&quot; alt=&quot;Ciclope-11&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;mountains-peak&quot;&gt;Mountains: peak&lt;/h3&gt;

&lt;p&gt;We are now far off route, but the top of the mountain has been calling us.&lt;/p&gt;

&lt;p&gt;We encounter indigenous people who have perhaps never seen a drone. Or maybe they are trying to take the package? We keep our distance and notice they seem preoccupied by something else.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There are markings on the rocks, including our familiar X marks the spot the recurring theme showing the place where we can set down our package and it will be safe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The people are looking for their pet. They understand that the drone might be able to help them and they shout in a language the drone does not recognise, but the new ability gained at the Valley means that we can understand them. We can see the pet stranded on a high peak.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If we fly directly there we will be in too much shadow and our battery will deplete. We figure out that we need to fly between crepuscular rays and avoid shadows. So with some aerial acrobatics and some picking up and dropping things to help the animal come closer, we are able to rescue pick it up and carry it back to the people. They reward us by interpreting the photo we took earlier and show us which way we need to go.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;we see: people, animals, the path forward&lt;/li&gt;
  &lt;li&gt;we feel: helpful, helped, oneness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-12.forest.jpg&quot; alt=&quot;Ciclope-12&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;forest&quot;&gt;Forest&lt;/h3&gt;

&lt;p&gt;We fly down the far side of the mountain. The scenery changes from snow covered peaks to lush forests. Never have we been able to fly so freely.&lt;/p&gt;

&lt;p&gt;Flying below tree canopy means less direct sun light and makes parts of this scenario more difficult. Imagine the Star Wars speedbike sequence.&lt;/p&gt;

&lt;p&gt;We are receiving radar signals for multiple power sources. One by one they drop off the radar, by going out of range, leaving us with only one. Little do we know that this is our last waypoint.&lt;/p&gt;

&lt;p&gt;We are hit by a catapulted projectile and crash to the ground. We see the crashed drone, open package, and the child picking up and using the music box.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: a human, a child&lt;/li&gt;
  &lt;li&gt;we feel: useful, happy, complete&lt;/li&gt;
  &lt;li&gt;we hear: the music box&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ciclope-13.fin.jpg&quot; alt=&quot;Ciclope-13&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;fin&quot;&gt;FIN&lt;/h3&gt;

&lt;p&gt;The end sequence is similar to the opening sequence, with the addition of humans. We see each location that we encountered in the game, but they are changed because the world is rebuilding. There are many drones, monorail systems and power source to be seen.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Delta: is once again the cradle of civilisation, busy with people and agriculture&lt;/li&gt;
  &lt;li&gt;Desert: is back online, populated and a hub of activity&lt;/li&gt;
  &lt;li&gt;Solar Farm: is now fully functional and even larger than before&lt;/li&gt;
  &lt;li&gt;Coastline: offshore wind farm, the monuments have been converted into windmills&lt;/li&gt;
  &lt;li&gt;Volcanic: we are harnessing the volcano heat and steam for power&lt;/li&gt;
  &lt;li&gt;Valley: we see a busy monorail system, and the waterfall and river is a power source&lt;/li&gt;
  &lt;li&gt;Storm: in daylight we see the electrified fence is another way of harnessing power&lt;/li&gt;
  &lt;li&gt;Peak: we see the indigenous people using technology to make their lives easier&lt;/li&gt;
  &lt;li&gt;Oasis: this turns out to be the home of the child, we see the drone being played with&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all, folks.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we see: everything&lt;/li&gt;
  &lt;li&gt;we feel: happy and content&lt;/li&gt;
  &lt;li&gt;we hear: rearranged main theme&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;post-credits&quot;&gt;Post Credits&lt;/h3&gt;

&lt;p&gt;The child is seen saving the sum total knowledge of her civilisation to a small magneto optical disc, inserting it into the music box, and loading it into the repaired drone. With great delight, she throws the drone into the air. Its next adventure begins.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;If it’s an open world can’t we just keep on flying?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;it is not an open world but a guided experience&lt;/li&gt;
  &lt;li&gt;each location is a limited dimensions and if we keep flying in one direction it will wrap around&lt;/li&gt;
  &lt;li&gt;this also help reduce backtracking if the map was wide open&lt;/li&gt;
  &lt;li&gt;travel between areas is guided but there is free movement within each area&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who is flying this thing?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;we are&lt;/li&gt;
  &lt;li&gt;slowly we will earn about other people in the world and we will be helped on our way by many of them, in a wide range of languages&lt;/li&gt;
  &lt;li&gt;with an ability gathered mid-game we can understand the languages&lt;/li&gt;
  &lt;li&gt;hearing all the messages will require a second play-through&lt;/li&gt;
  &lt;li&gt;messages that initially appeared angry take on other meanings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do we segue between locations?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;music &amp;amp; animated sequence almost like a music visualiser
    &lt;ul&gt;
      &lt;li&gt;like the star-filled sky @1:38&lt;/li&gt;
      &lt;li&gt;and the sun-bleached sky @1:48&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;we have to rest (sleep) in some locations to progress from night to day&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;influences&quot;&gt;Influences&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/パネキット&quot;&gt;Panekit&lt;/a&gt; (1999, PS1)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Rime_(video_game)&quot;&gt;Rime&lt;/a&gt; (2017, PS4)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Journey_(2012_video_game)&quot;&gt;Journey&lt;/a&gt; (2021, PS3)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Proteus_(video_game)&quot;&gt;Proteus&lt;/a&gt; (2013, PC)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ico&quot;&gt;Ico&lt;/a&gt; (2001, PS2)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hunter_(video_game)&quot;&gt;Hunter&lt;/a&gt; (1991, Atari ST)&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 01 Jun 2024 14:30:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/06/01/pitching-a-game-based-on-the-ciclope-2016-opening-film/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/06/01/pitching-a-game-based-on-the-ciclope-2016-opening-film/</guid>
        </item>
      
    
      
        <item>
          <title>Mouse Support for Playdate</title>
          <description>&lt;p&gt;Since some of my first prototypes with Playdate I’ve wanted there to be a way to interact with the device using a mouse. Well, today is that day!&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 3/2;&quot; videoid=&quot;PF4emlHhYCM&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;No doubt you have some questions? How are you doing this? What’s the weather like? etc.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how&quot;&gt;How?&lt;/h2&gt;

&lt;p&gt;A custom &lt;a href=&quot;https://www.hammerspoon.org&quot;&gt;Hammerspoon&lt;/a&gt; script monitors mouse coordinates and sends them to the Playdate over serial connection. The game receives those messages through the recently added API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;playdate.serialMessageReceived(message)&lt;/code&gt;, parses them, and acts accordingly.&lt;/p&gt;

&lt;p&gt;Currently the script sends messages such as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;msg mouse on
msg 0,0
msg -19,84
msg mouse off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use those to trigger on screen notifications, reset the game state, and move the cursor.&lt;/p&gt;

&lt;p&gt;Note: use of serial means you can’t have the Playdate Simulator or Mirror open when trying this. If you invoke the script and it can’t open the serial connection for any reason it will sound an error beep.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;

&lt;p&gt;Originally, back in 2020, I wanted to be able to position items in the in-game level editor of &lt;a href=&quot;/tag/dailydriver/&quot;&gt;my game Daily Driver&lt;/a&gt; more directly, using a mouse rather than typing co-ordinates into a file. Then I forgot about it for a while. Then in &lt;a href=&quot;https://sdk.play.date/changelog/#_2_4_0&quot;&gt;&lt;em&gt;Playdate SDK 2.4.0&lt;/em&gt;&lt;/a&gt; (March 1, 2024) a new API was added that made me wonder if it was now possible.&lt;/p&gt;

&lt;p&gt;I knew the &lt;a href=&quot;https://itch.io/jam/uncrankdjam&quot;&gt;Uncrank’d Game Jam&lt;/a&gt; was in progress and was thinking about what to do, and then the mouse control idea came back to me. I first put together the bare bones of an app that drew a dot to the screen, mirrored both horizontally and vertically. Then I set about proving I could forward mouse events, which resulted in a &lt;a href=&quot;https://github.com/gingerbeardman/playdate-mouse-support/blob/main/mouse/mouse_to_playdate.lua&quot;&gt;small Hammerspoon script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that, I built out the drawing app and that’s how &lt;a href=&quot;https://gingerbeardman.itch.io/rorschach&quot;&gt;Rorschach&lt;/a&gt; came to be. It was originally built to showcase the mouse control, but has since evolved into a lovely little toy of its own. I thought a drawing app would be an easy-to-understand visual showcase for this innovation. But, really, the possibilities for its use are endless.&lt;/p&gt;

&lt;p&gt;Developers can use it to speed up and simplify development, add finer control to their in-game level editors, and generally make their lives easier. There’s nothing stopping you giving users access to it in a game.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Make sure you’re running &lt;a href=&quot;https://gingerbeardman.itch.io/rorschach&quot;&gt;Rorschach&lt;/a&gt; or &lt;a href=&quot;https://github.com/gingerbeardman/playdate-mouse-support/releases/tag/240511&quot;&gt;Mouse Demo&lt;/a&gt; on your device&lt;/li&gt;
  &lt;li&gt;Attach your Playdate over USB and unlock the device&lt;/li&gt;
  &lt;li&gt;Install &lt;a href=&quot;https://www.hammerspoon.org/&quot;&gt;Hammerspoon&lt;/a&gt; automation tool for macOS&lt;/li&gt;
  &lt;li&gt;Install &lt;a href=&quot;https://github.com/gingerbeardman/playdate-mouse-support/blob/main/mouse/mouse_to_playdate.lua&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mouse_to_playdate.lua&lt;/code&gt;&lt;/a&gt; (instructions in the file)&lt;/li&gt;
  &lt;li&gt;Press the hotkey (defaults to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F13&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;The guide window (virtual trackpad?) appears so you can gauge Playdate screen size&lt;/li&gt;
  &lt;li&gt;Move your mouse pointer and watch the drawing appear!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ve tested this on a MBP running Sonoma with a mouse and a trackpad. There’s very little lag, it’s really quite usable. The video has substantial lag as I was capturing through QuickTime and my phone camera. Anyway, it’s super cool!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;demos&quot;&gt;Demos&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Rorschach drawing app is at: &lt;a href=&quot;https://gingerbeardman.itch.io/rorschach&quot;&gt;gingerbeardman.itch.io/rorschach&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;An example project with source code is at: &lt;a href=&quot;https://github.com/gingerbeardman/playdate-mouse-support&quot;&gt;github.com/gingerbeardman/playdate-mouse-support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;This is a technical proof of concept, so it can be improved&lt;/li&gt;
  &lt;li&gt;It was created to show that this can be done. It is not a final version or the most robust way of doing this. And, yes, sorry, it’s only available for macOS&lt;/li&gt;
  &lt;li&gt;My dream scenario would be for Playdate Simulator and Mirror to have this feature built-in, so you can enable the feature and then interact with the virtual screen to forward mouse events to Playdate&lt;/li&gt;
  &lt;li&gt;If that can’t happen, then maybe a more native mouse forwarding client can be created for each of macOS, Windows, and Linux&lt;/li&gt;
  &lt;li&gt;On macOS it would be cool if it supported Apple Pencil via an iPad/Sidecar&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 11 May 2024 10:52:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/05/11/mouse-support-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/05/11/mouse-support-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>A year in the life of a Playdate game developer</title>
          <description>&lt;p&gt;This week sees the &lt;a href=&quot;https://play.date/games/tags/on-sale&quot;&gt;first Anniversary Sale of Catalog, the official store for Playdate games&lt;/a&gt;. This means it’s almost the anniversary of &lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;the release Sparrow Solitaire&lt;/a&gt;, which was the first Playdate work I did in 2023 after taking an enforced break.&lt;/p&gt;

&lt;p&gt;So I thought it would be interesting to look back and take stock of the last year of me making stuff for Playdate. What did I finish? What did I abandon? What is still to come?&lt;/p&gt;

&lt;p&gt;After Sparrow Solitaire (a huge game that took around a year of development time split between myself and Mac Vogelsang), it took me a few months to figure out the right sort of size and scope that would allow me to make a game every month or two, whilst minimising the risk of not selling enough. By September I was well and truly &lt;em&gt;in the zone&lt;/em&gt; and &lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;created YOYOZO&lt;/a&gt; which went on to receive a commendation from Ars Technica as one of the &lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;“Best Games of 2023”&lt;/a&gt;. And at the &lt;a href=&quot;https://play.date/games/community-awards-2023/&quot;&gt;2023 Playdate Community Awards&lt;/a&gt;, presented on 8th March 2024, Sparrow Solitaire won &lt;em&gt;Best Puzzle Game&lt;/em&gt; and YOYOZO won &lt;em&gt;Best Arcade Game&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Somebody asked me if this is my full-time job? My answer is: yes, this is my only job and I do it as often as I’m able. It’s certainly more complicated, due to various life stuff, but that’s the gist of things. Over the last twelve months, I would say I’ve been productive for around half my time.&lt;/p&gt;

&lt;p&gt;Recently I saw somebody say &lt;a href=&quot;https://twitter.com/indieretropod/status/1764443576597946593&quot;&gt;“Be careful with scope and look what you can do in a year!”&lt;/a&gt;, about the wonderful &lt;a href=&quot;https://twitter.com/johanpeitz&quot;&gt;Johan Peitz&lt;/a&gt;, and I think that addage can also be applied to my output this year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; 22 projects, 10 of which were released, and 5 are still to come. I’m pretty happy with that!&lt;/p&gt;

&lt;p&gt;I also managed to squeeze in a couple of non-Playdate projects: my first real Love2D game &lt;a href=&quot;https://gingerbeardman.itch.io/portrait-curling&quot;&gt;Portrait Curling&lt;/a&gt;, modifications to vintage pixel art app &lt;a href=&quot;/2024/01/22/jinzo-paint-vintage-mobile-drawing-app/&quot;&gt;JINZO Paint&lt;/a&gt;, and I’m always &lt;a href=&quot;/&quot;&gt;blogging&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don’t forget to &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;check out my Playdate games in the Catalog Sale!&lt;/a&gt; And my &lt;a href=&quot;/tag/playdate/&quot;&gt;other Playdate blog posts&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Month&lt;/th&gt;
        &lt;th&gt;Project&lt;/th&gt;
        &lt;th&gt;Genre&lt;/th&gt;
        &lt;th&gt;Status&lt;/th&gt;
        &lt;th&gt;Store&lt;/th&gt;
        &lt;th&gt;Blog&lt;/th&gt;
        &lt;th&gt;Made With&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-03&lt;/td&gt;
        &lt;td&gt;Sparrow Solitaire&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/sparrow-solitaire/&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/sparrow-solitaire/&quot;&gt;Catalog&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;Read&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://twitter.com/Vogelscript&quot;&gt;vogelscript&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-04&lt;/td&gt;
        &lt;td&gt;Shark Turtle&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;Unreleased&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-05&lt;/td&gt;
        &lt;td&gt;Radical&lt;/td&gt;
        &lt;td&gt;Adventure&lt;/td&gt;
        &lt;td&gt;Abandoned&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-05&lt;/td&gt;
        &lt;td&gt;Carton&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;On hold&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-06&lt;/td&gt;
        &lt;td&gt;Heno Heno&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;On hold&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-06&lt;/td&gt;
        &lt;td&gt;Fore! Track&lt;/td&gt;
        &lt;td&gt;Sports&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;Catalog&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Read&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-07&lt;/td&gt;
        &lt;td&gt;Mandala&lt;/td&gt;
        &lt;td&gt;Toy&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://github.com/gingerbeardman/mandala&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;GitHub&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-08&lt;/td&gt;
        &lt;td&gt;Strategies&lt;/td&gt;
        &lt;td&gt;App&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/strategies&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;Itch&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-08&lt;/td&gt;
        &lt;td&gt;DateDiff&lt;/td&gt;
        &lt;td&gt;App&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/datediff&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;Itch&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-08&lt;/td&gt;
        &lt;td&gt;Fortress&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;Abandoned&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-08&lt;/td&gt;
        &lt;td&gt;Mole Hole&lt;/td&gt;
        &lt;td&gt;Adventure&lt;/td&gt;
        &lt;td&gt;Unreleased&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://twitter.com/thoruman&quot;&gt;thoruman&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-09&lt;/td&gt;
        &lt;td&gt;Rink&lt;/td&gt;
        &lt;td&gt;Sports&lt;/td&gt;
        &lt;td&gt;Tutorial&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-09&lt;/td&gt;
        &lt;td&gt;Kye&lt;/td&gt;
        &lt;td&gt;Puzzle&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://mouflon-cloud.itch.io/kye&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;Itch&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://twitter.com/MouflonCloud&quot;&gt;mouflon cloud&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-09&lt;/td&gt;
        &lt;td&gt;YOYOZO&lt;/td&gt;
        &lt;td&gt;Action&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;Catalog&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;Read&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-10&lt;/td&gt;
        &lt;td&gt;Pararena&lt;/td&gt;
        &lt;td&gt;Sports&lt;/td&gt;
        &lt;td&gt;Abandoned&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-10&lt;/td&gt;
        &lt;td&gt;Soccer&lt;/td&gt;
        &lt;td&gt;Sports&lt;/td&gt;
        &lt;td&gt;Prototype&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-10&lt;/td&gt;
        &lt;td&gt;Super ICARUS&lt;/td&gt;
        &lt;td&gt;Action&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://play.date/games/icarus/&quot;&gt;Catalog&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-11&lt;/td&gt;
        &lt;td&gt;Boing&lt;/td&gt;
        &lt;td&gt;Action&lt;/td&gt;
        &lt;td&gt;Prototype&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-11&lt;/td&gt;
        &lt;td&gt;Cranxious&lt;/td&gt;
        &lt;td&gt;Action&lt;/td&gt;
        &lt;td&gt;Prototype&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2023-12&lt;/td&gt;
        &lt;td&gt;See The Sky&lt;/td&gt;
        &lt;td&gt;Storybook&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/see-the-sky&quot;&gt;Released&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;Itch&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;/2023/12/16/see-the-sky-thoru-yamamoto-christmas-story-for-playdate/&quot;&gt;Read&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;https://twitter.com/thoruman&quot;&gt;thoruman&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2024-01&lt;/td&gt;
        &lt;td&gt;Rocket Man&lt;/td&gt;
        &lt;td&gt;Simulation&lt;/td&gt;
        &lt;td&gt;On hold&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2024-02&lt;/td&gt;
        &lt;td&gt;Eggdog&lt;/td&gt;
        &lt;td&gt;Action&lt;/td&gt;
        &lt;td&gt;Prototype&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 07 Mar 2024 19:44:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/03/07/a-year-in-the-life-of-a-playdate-game-developer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/03/07/a-year-in-the-life-of-a-playdate-game-developer/</guid>
        </item>
      
    
      
        <item>
          <title>Interview: Kenta Cho (Japanese indie game developer)</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/dev2dev-kenta-cho.jpg&quot; alt=&quot;Kenta Cho&quot; title=&quot;Kenta Cho&quot; class=&quot;profile&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Kenta Cho&lt;/em&gt; is a Japanese indie game developer, who has been active since the 1980s. He became well-known in the West in the early 2000s with a series of bullet hell shoot-em-ups. In 2021 he created a total 139 games, which is one hell of a lockdown project. In early 2024 his game &lt;a href=&quot;https://abagames.github.io/crisp-game-lib-11-games/?pakupaku&quot;&gt;&lt;em&gt;Paku Paku&lt;/em&gt;&lt;/a&gt; went viral, as “&lt;em&gt;1D Pac-Man&lt;/em&gt;”, a year after it was made.&lt;/p&gt;

&lt;p&gt;I reached out to him with some questions and he was gracious enough to answer them candidly, from one game developer to another.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;ive-been-following-your-work-for-20-years-at-this-point-so-id-like-to-know-more-about-you-as-a-person-and-a-game-developer-can-you-please-share-some-details-about-your-background-and-current-professional-status&quot;&gt;I’ve been following your work for 20 years at this point, so I’d like to know more about you as a person and a game developer. Can you please share some details about your background and current professional status?&lt;/h2&gt;

&lt;p&gt;After studying information science at university, I joined a manufacturing company in an IT-related research position. Currently, I work as a manager in system development. I have never worked in the gaming industry.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;wow-youre-a-true-indie-in-that-youve-never-worked-at-a-game-studio-well-lets-start-at-the-beginning-what-was-your-earliest-experience-with-video-games&quot;&gt;Wow! You’re a true indie in that you’ve never worked at a game studio! Well, let’s start at the beginning: what was your earliest experience with video games?&lt;/h2&gt;

&lt;p&gt;It was &lt;em&gt;Nintendo&lt;/em&gt;’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Game_&amp;amp;_Watch&quot;&gt;&lt;em&gt;Game &amp;amp; Watch&lt;/em&gt;&lt;/a&gt;. Around that time, I lived in an apartment, and I used to exchange and play various &lt;em&gt;Game &amp;amp; Watch&lt;/em&gt; games with my friends who lived there. Titles like &lt;em&gt;Fire&lt;/em&gt;, &lt;em&gt;Manhole&lt;/em&gt;, &lt;em&gt;Helmet&lt;/em&gt;, &lt;em&gt;Parachute&lt;/em&gt;, and &lt;em&gt;Octopus&lt;/em&gt; were simple yet extremely exciting. The simple gameplay of &lt;em&gt;Game &amp;amp; Watch&lt;/em&gt; has become my foundational experience in gaming, significantly influencing the small games I make now.&lt;/p&gt;

&lt;p&gt;Also, at that time, game arcades were more adult-oriented, making it difficult for children to visit, so arcade games were objects of longing that I couldn’t actually play. Instead, there were various LSI/FL games (in the West we usually refer to such games as LCD games or handheld electronic games) that ported those arcade games, which I also played with friends. Games like &lt;a href=&quot;https://en.wikipedia.org/wiki/Heiankyo_Alien&quot;&gt;&lt;em&gt;Heiankyo Alien&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Frisky_Tom&quot;&gt;&lt;em&gt;Frisky Tom&lt;/em&gt;&lt;/a&gt;, ported to machines with specs far inferior to arcade games, were almost different games, but their core gameplay was well-designed, and I loved playing them. The LSI game version of &lt;a href=&quot;https://en.wikipedia.org/wiki/Pac-Man&quot;&gt;&lt;em&gt;Pac-Man&lt;/em&gt;&lt;/a&gt;, released by multiple manufacturers, was interesting because each one had its unique arrangement. It was enlightening to realize that depending on the arrangement, a variety of variations could be created from the base gameplay, which greatly influenced my game development.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Game_%26_Watch_games&quot;&gt;List of Game &amp;amp; Watch games&lt;/a&gt; at Wikipedia&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://handheldmuseum.com&quot;&gt;Handheld Games Museum&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;so-even-in-these-early-days-you-were-captivated-by-simple-and-effective-gameplay-was-it-at-this-point-that-you-began-programming-computers&quot;&gt;So even in these early days you were captivated by simple and effective gameplay. Was it at this point that you began programming computers?&lt;/h2&gt;

&lt;p&gt;I was about ten years old when I saw a TV educational program called マイコン入門 “Mycom Nyumon” (Introduction to Microcomputers). “Mycom” is another name for microcomputer, which was the term used during the dawn of personal computers in Japan. At that time, it was very rare for households to own a personal computer, hence the microcomputer was colloquially called “Mycom”, short for “My-computer”. “Mycom Nyumon” was a program aimed at complete beginners to computers, explaining things like programming. Watching how computers could perform various calculations and control the screen, I thought they were like magical boxes and was utterly fascinated.&lt;/p&gt;

&lt;p&gt;Later, my father bought a &lt;a href=&quot;https://en.wikipedia.org/wiki/Sharp_PC-1500&quot;&gt;&lt;em&gt;SHARP PC-1500&lt;/em&gt;&lt;/a&gt;, a pocket computer, and brought it home. That was my first experience with programming in &lt;a href=&quot;https://en.wikipedia.org/wiki/BASIC&quot;&gt;&lt;em&gt;BASIC&lt;/em&gt;&lt;/a&gt;, and I thought it had potential unlike any machine I had seen before.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/マイコン入門&quot;&gt;マイコン入門 (Introduction to Microcomputers)&lt;/a&gt; at Wikipedia (Japanese)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/ポケットコンピュータ&quot;&gt;ポケットコンピュータ (Pocket computer)&lt;/a&gt; at Wikipedia (Japanese)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.epocalc.net/php/liste_comp.php?type1=PC&amp;amp;type2=MF&amp;amp;type3=MC&amp;amp;type4=SC&amp;amp;type5=TER&amp;amp;type6=SU&amp;amp;type7=%3F&amp;amp;cat=POCKET&amp;amp;sel=all&amp;amp;ystart=1940&amp;amp;yend=2019&amp;amp;actu=all&amp;amp;order=manuf/&quot;&gt;Pocket Computer Manufacturers Database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;despite-the-limitation-of-the-single-line-display-on-those-pocket-computers-they-were-host-to-many-great-games-i-can-see-their-influence-in-your-games-today-atwhat-point-did-you-decide-to-create-your-own-game&quot;&gt;Despite the limitation of the single line display on those pocket computers they were host to many great games. I can see their influence in your games today. At what point did you decide to create your own game?&lt;/h2&gt;

&lt;p&gt;The next microcomputer we got was the &lt;a href=&quot;https://en.wikipedia.org/wiki/NEC_PC-6001&quot;&gt;&lt;em&gt;NEC PC-6001&lt;/em&gt;&lt;/a&gt;. This was a type that connected to a TV. It was a fresh experience to turn the TV, usually just for watching shows, into something interactive that could be operated with keystrokes and programming. At first, I created games in &lt;em&gt;BASIC&lt;/em&gt;, but I was dissatisfied with the processing speed for action games, so I learned to hand-assemble for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Zilog_Z80&quot;&gt;&lt;em&gt;Z-80&lt;/em&gt;&lt;/a&gt; and began creating games in &lt;a href=&quot;https://en.wikipedia.org/wiki/Machine_code&quot;&gt;&lt;em&gt;machine language&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Japan, there was a magazine called マイコンBASICマガジン “&lt;em&gt;Mycom BASIC Magazine&lt;/em&gt;” that accepted submissions of game programs from readers and published them. Each game in the magazine had several pages of source code, which you would enter manually to play the game. These games, despite their compact source code, were full of originality. There were action games about making hamburgers as ordered, race games combined with &lt;em&gt;Pac-Man&lt;/em&gt;’s power pellets, puzzle games incorporating rock-paper-scissors, etc. Inspired by how such diverse games could be created depending on the idea, I wanted to make such games too.&lt;/p&gt;

&lt;p&gt;I tried submitting some games I made to “&lt;em&gt;Mycom BASIC Magazine&lt;/em&gt;”, but it was tough to get them accepted. Only one got published – &lt;em&gt;METEORITE&lt;/em&gt; - a game where you shoot down meteors falling from the sky. The game had a unique control where the position of the keys on the keyboard was linked to the attack position on the screen, and you determined the attack location by pressing the keyboard with a clenched fist.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/マイコンBASICマガジン&quot;&gt;Mycom BASIC Magazine&lt;/a&gt; at Wikipedia (Japanese)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/basiccomputingmagazine&quot;&gt;Mycom BASIC Magazine&lt;/a&gt; at Internet Archive&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/micomBASIC-1989-09/page/139/mode/1up&quot;&gt;&lt;em&gt;METEORITE&lt;/em&gt;—source code&lt;/a&gt; in the 1989-09 issue of Mycom BASIC Magazine&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/files/meteorite-by-kenta-cho-from-mycom-basic-magazine-1989-09.p6t&quot;&gt;&lt;em&gt;METEORITE&lt;/em&gt;—tape file&lt;/a&gt; for use with a PC-6001 emulator&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Thanks to Dustin Hubbard (Hubz)&lt;/em&gt; at &lt;a href=&quot;https://www.gamingalexandria.com&quot;&gt;&lt;em&gt;Gaming Alexandria&lt;/em&gt;&lt;/a&gt; for transforming the magazine source code listing into a tape image. This was done using specialist Japanese software &lt;a href=&quot;https://github.com/eighttails/ProgramListOCR&quot;&gt;&lt;em&gt;ProgamListOCR&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://bugfire2009.ojaru.jp/input.html&quot;&gt;&lt;em&gt;DumpListEditor&lt;/em&gt;&lt;/a&gt; that are tailor-made for getting old source code off the page and into the computer, so thanks also to the authors of those applications. Video game preservation is a worldwide effort.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/dev2dev-kenta-cho-meteorite.jpg&quot; alt=&quot;METEORITE source code in 1989-09 issue of Mycom BASIC Magazine&quot; title=&quot;METEORITE source code in 1989-09 issue of Mycom BASIC Magazine&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;your-formative-years-coincided-with-the-golden-age-of-video-games-period-from-the-late-1970s-to-the-early-1980s-what-inspired-you-at-that-time&quot;&gt;Your formative years coincided with the “golden age of video games” period from the late 1970s to the early 1980s. What inspired you at that time?&lt;/h2&gt;

&lt;p&gt;It was &lt;a href=&quot;https://en.wikipedia.org/wiki/Namco&quot;&gt;&lt;em&gt;Namco&lt;/em&gt;&lt;/a&gt;’s arcade games. In the 1980s arcade games, I felt that the ideas in games released by &lt;em&gt;Namco&lt;/em&gt; were particularly excellent. &lt;a href=&quot;https://en.wikipedia.org/wiki/Dig_Dug&quot;&gt;&lt;em&gt;Dig Dug&lt;/em&gt;&lt;/a&gt;’s one-shot reversal reward using rocks and the risk of being crushed by them, &lt;a href=&quot;https://en.wikipedia.org/wiki/Xevious&quot;&gt;&lt;em&gt;Xevious&lt;/em&gt;&lt;/a&gt;’ beautiful graphics and well-crafted enemy flight curves, &lt;a href=&quot;https://en.wikipedia.org/wiki/Gaplus&quot;&gt;&lt;em&gt;Gaplus&lt;/em&gt;&lt;/a&gt;’ super-fast enemy movements yet fair game balance, and &lt;a href=&quot;https://en.wikipedia.org/wiki/New_Rally-X&quot;&gt;&lt;em&gt;New Rally-X&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Bosconian&quot;&gt;&lt;em&gt;Bosconian&lt;/em&gt;&lt;/a&gt;’s combination of all-direction scrolling and radar screens requiring complex situational judgment – &lt;em&gt;Namco&lt;/em&gt; kept releasing games with very innovative mechanisms. A lot of my belief in the importance of novel mechanisms in game production comes from encountering &lt;em&gt;Namco&lt;/em&gt;’s arcade games during this era.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Namco_games#Namco_proprietary_arcade_systems&quot;&gt;List of Namco arcade games&lt;/a&gt; at Wikipedia&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;i-apologise-for-this-next-question-as-its-almost-impossibly-difficult-but-im-keen-to-learn-more-about-you-from-the-games-you-like-to-play-so-what-are-five-of-your-favourite-video-games-and-what-aspects-make-them-special-to-you&quot;&gt;I apologise for this next question, as it’s almost impossibly difficult, but I’m keen to learn more about you from the games you like to play. So… what are five of your favourite video games, and what aspects make them special to you?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Transport_Tycoon&quot;&gt;&lt;strong&gt;Transport Tycoon&lt;/strong&gt;&lt;/a&gt;—it’s a railway management simulator, released by &lt;a href=&quot;https://en.wikipedia.org/wiki/MicroProse&quot;&gt;&lt;em&gt;MicroProse&lt;/em&gt;&lt;/a&gt;. I also liked its predecessor, &lt;a href=&quot;https://en.wikipedia.org/wiki/Railroad_Tycoon&quot;&gt;&lt;em&gt;Railroad Tycoon&lt;/em&gt;&lt;/a&gt;, but I played &lt;em&gt;Transport Tycoon&lt;/em&gt; for a longer time. A major difference between the two is that in &lt;em&gt;Transport Tycoon&lt;/em&gt;, there are rival companies laying tracks on the same map. It was fun to strategize and lay tracks aggressively to important cities to beat rivals. It’s my favorite game in the city development simulation genre. The isometric beautiful graphics and lively BGM (background music) were great too.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/DoDonPachi&quot;&gt;&lt;strong&gt;Dodonpachi&lt;/strong&gt;&lt;/a&gt;—the first title in &lt;a href=&quot;https://en.wikipedia.org/wiki/Cave_(company)&quot;&gt;&lt;em&gt;CAVE&lt;/em&gt;&lt;/a&gt;’s famous &lt;em&gt;Dodonpachi&lt;/em&gt; series of bullet hell vertical scrolling shooters, following its progenitor, &lt;a href=&quot;https://en.wikipedia.org/wiki/Donpachi&quot;&gt;&lt;em&gt;Donpachi&lt;/em&gt;&lt;/a&gt;. A fun aspect of bullet hell shooters is the technique called “cutback”. It involves rapidly moving the player to one screen edge to create gaps in bullet patterns, then escaping in the opposite direction through these gaps. &lt;em&gt;Dodonpachi&lt;/em&gt;’s stage 5 offers the best experience of this, influencing the shooting games I would create later.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ikaruga&quot;&gt;&lt;strong&gt;Ikaruga&lt;/strong&gt;&lt;/a&gt;—a vertical scrolling shooter with a unique system where both the player and enemy bullets have black and white attributes, and bullets of the same attribute can be absorbed. This system provided a gameplay experience quite different from previous shooters. Although released as an arcade game, perhaps thinking it too different for ordinary players to accept as is, the first stage offered an “infinite lives trial game” mode. At first, I had no idea when to switch attributes and was helplessly defeated many times. But once I understood which enemies to attack with which attribute and when, the game became addictively charming. The chain combo for defeating three enemies of the same attribute in succession and the complex attack patterns of stage 4’s so-called “Rafflesia” added to its depth. The groundbreaking game system offered an artistic playing experience, impressing me with the high potential of gaming.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Atlas_(video_game)&quot;&gt;&lt;strong&gt;THE ATLAS&lt;/strong&gt;&lt;/a&gt;—a PC exploration game set during the &lt;a href=&quot;https://en.wikipedia.org/wiki/Age_of_Discovery&quot;&gt;&lt;em&gt;Age of Discovery&lt;/em&gt;&lt;/a&gt;, released by &lt;a href=&quot;https://en.wikipedia.org/wiki/Artdink&quot;&gt;&lt;em&gt;ArtDink&lt;/em&gt;&lt;/a&gt;. Its feature was a procedurally generated coastline, different in each game. The player dispatches a captain from Lisbon to survey coastlines and ports. Upon the captain’s return, you can choose to “believe” or “disbelieve” their report. Disbelieving discards the survey results, but here comes the twist with the procedural generation. If the captain reports an endlessly long, supply-challenged coastline, or a closed one preventing further survey, disbelieving it could generate a more advantageous coastline in the next survey. The game skilfully integrated procedural mechanics with the game system, deeply enlightening me about the benefits of incorporating procedural elements into games.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Rez_(video_game)&quot;&gt;&lt;strong&gt;Rez&lt;/strong&gt;&lt;/a&gt;—a 3D shooter with abstract wireframe graphics and techno music synchronized with sound effects. The immersion provided by this game was unique, supported by the excellence of its visuals and music. Especially, the sound effects being quantized to match the background music’s rhythm and beat, making game operations and actions feel like playing an instrument, was brilliant. I have incorporated a similar quantization mechanism in the games I’m creating now.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;i-see-a-nice-balance-of-gameplay-systems-and-skill-in-all-of-those-games-that-brings-to-mind-the-types-of-games-you-create-now-if-you-could-have-developed-any-existing-game-which-one-would-you-choose-and-why&quot;&gt;I see a nice balance of gameplay systems and skill in all of those games. That brings to mind the types of games you create. Now, if you could have developed any existing game, which one would you choose, and why?&lt;/h2&gt;

&lt;p&gt;That’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Herzog_(video_game)&quot;&gt;&lt;em&gt;Herzog&lt;/em&gt;&lt;/a&gt;. It’s a real-time strategy game released by &lt;a href=&quot;https://en.wikipedia.org/wiki/Technosoft&quot;&gt;&lt;em&gt;Technosoft&lt;/em&gt;&lt;/a&gt; for personal computers. Overseas, the sequel &lt;a href=&quot;https://en.wikipedia.org/wiki/Herzog_Zwei&quot;&gt;&lt;em&gt;Herzog Zwei&lt;/em&gt;&lt;/a&gt;, which was released for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Sega_Mega_Drive&quot;&gt;&lt;em&gt;Sega Mega Drive&lt;/em&gt;&lt;/a&gt;, is more famous, and the original &lt;em&gt;Herzog&lt;/em&gt; might not be as well-known. It’s an action game where you control a robot that can move both in the air and on the ground. The battlefield is a vertically long strip, with enemy and ally bases located at each end. Players could produce units like infantry, tanks, and anti-aircraft guns at these bases and dispatch them towards the opponent’s base. At that time, it was quite rare to have a game where you could produce allies other than the player and fight together. I was very impressed by this game, where you could fight as part of an army against enemy forces.&lt;/p&gt;

&lt;p&gt;Later, I even created a game similar to &lt;em&gt;Herzog&lt;/em&gt; for the &lt;a href=&quot;https://en.wikipedia.org/wiki/PC-98&quot;&gt;&lt;em&gt;PC-9801&lt;/em&gt;&lt;/a&gt;. I made the screen 3D and added an arrangement where you could freely board any friendly unit on the battlefield, intending to make the game even more enjoyable.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=MU2FDnKzt5I&quot;&gt;Herzog (MSX) longplay&lt;/a&gt; on YouTube&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-the-early-2000s-many-western-gamers-developed-a-real-interest-in-japanese-indie-games-particularly-shoot-em-ups-shmups-you-gained-recognition-for-multiple-shmups-and-you-were-even-interviewed-by-mtv-can-you-share-any-experiences-from-that-period&quot;&gt;In the early 2000s many Western gamers developed a real interest in Japanese indie games, particularly shoot-‘em-ups (shmups). You gained recognition for multiple shmups, and you were even interviewed by &lt;em&gt;MTV&lt;/em&gt;! Can you share any experiences from that period?&lt;/h2&gt;

&lt;p&gt;At that time, I often played bullet hell shooters released by &lt;em&gt;CAVE&lt;/em&gt; at game arcades, especially loving &lt;a href=&quot;https://en.wikipedia.org/wiki/Progear_no_Arashi&quot;&gt;&lt;em&gt;Progear no Arashi&lt;/em&gt;&lt;/a&gt;. &lt;em&gt;Progear&lt;/em&gt;’s bullet patterns were very complex compared to earlier &lt;em&gt;CAVE&lt;/em&gt; games, like fan-shaped bullets shot in nine directions, slowly decelerating, and then five straight bullets targeting the player. I wanted to replicate such complex bullet movements in a simple way and developed the &lt;em&gt;BulletML&lt;/em&gt; language.&lt;/p&gt;

&lt;p&gt;With &lt;em&gt;BulletML&lt;/em&gt;, I developed &lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/windows/noiz2sa_e.html&quot;&gt;&lt;em&gt;Noiz2sa&lt;/em&gt;&lt;/a&gt;, aiming to achieve the fun of bullet hell dodging with the immersion of games like &lt;em&gt;Rez&lt;/em&gt;. In &lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/windows/rr_e.html&quot;&gt;&lt;em&gt;rRootage&lt;/em&gt;&lt;/a&gt;, I used &lt;em&gt;BulletML&lt;/em&gt; for procedural generation of bullet patterns, aiming to create infinite attack patterns. After developing a technology called &lt;em&gt;Bulletsmorph&lt;/em&gt; and extensive balancing, I finally released it. It was challenging to achieve patterns that were fair and challenging without reducing variation, but I think it worked out well. Among my shooting games often featuring auto-generated levels, &lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/windows/tf_e.html&quot;&gt;&lt;em&gt;TUMIKI Fighters&lt;/em&gt;&lt;/a&gt;, where levels were manually designed, was somewhat unique. But this was simply because I found &lt;em&gt;Namco&lt;/em&gt;’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Katamari_Damacy&quot;&gt;&lt;em&gt;Katamari Damacy&lt;/em&gt;&lt;/a&gt; so enjoyable that I wanted to combine it with a shooting game. Attaching enemies to your ship until it occupies more than half the screen, this kind of shooting game is still quite rare, so I think it turned out to be a game with originality.&lt;/p&gt;

&lt;p&gt;Also, during this period, I entered various game contests with my games. Games for the &lt;a href=&quot;https://en.wikipedia.org/wiki/WonderSwan&quot;&gt;&lt;em&gt;WonderSwan&lt;/em&gt;&lt;/a&gt; on &lt;a href=&quot;https://ja.wikipedia.org/wiki/ワンダーウィッチ&quot;&gt;&lt;em&gt;WonderWitch&lt;/em&gt;&lt;/a&gt;, games for &lt;em&gt;Xbox 360&lt;/em&gt; on &lt;a href=&quot;https://en.wikipedia.org/wiki/Microsoft_XNA&quot;&gt;&lt;em&gt;XNA&lt;/em&gt;&lt;/a&gt;, and games for contests on &lt;a href=&quot;/2021/08/19/aquaplus-piece-vs-panic-playdate/&quot;&gt;&lt;em&gt;P/ECE&lt;/em&gt;&lt;/a&gt;. Fortunately, some games won awards. I had opportunities to present my games to judges, which was enjoyable. Playing my games on these consumer devices was a fresh experience for an amateur developer. Also, optimizing for each device’s characteristics provided many interesting development experiences.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/windows.html&quot;&gt;Kenta Cho’s Windows games&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/misc.html&quot;&gt;Kenta Chu’s miscellaneous games&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-the-following-years-i-continued-to-follow-your-work-and-noticed-a-move-towards-the-web-browser-as-your-platform-of-choice-more-recently-i-was-wowed-by-your-prolific-output-particularly-the-139-games-you-made-in-2021-im-wondering-what-motivates-you-and-can-you-outline-your-creative-process&quot;&gt;In the following years I continued to follow your work and noticed a move towards the web browser as your platform of choice. More recently, I was wowed by your prolific output, particularly the 139 games you made in 2021! I’m wondering, what motivates you? And can you outline your creative process?&lt;/h2&gt;

&lt;p&gt;Around 2008, I realized I could make browser-playable games by implementing them in &lt;a href=&quot;https://en.wikipedia.org/wiki/ActionScript#2006–2020:_ActionScript_3.0&quot;&gt;&lt;em&gt;ActionScript3&lt;/em&gt;&lt;/a&gt;, a programming language for &lt;a href=&quot;https://en.wikipedia.org/wiki/Adobe_Flash&quot;&gt;&lt;em&gt;Flash&lt;/em&gt;&lt;/a&gt;. I knew about &lt;em&gt;Flash&lt;/em&gt;, but I thought of it more as a platform for creating animations than games. However, &lt;em&gt;ActionScript3&lt;/em&gt; was a sophisticated language with diverse features, allowing me to create games using just code. Browser games are more accessible than conventional games, so I started making many small action games that could be played intuitively in a short time.&lt;/p&gt;

&lt;p&gt;Through this process, I realized that making lots of small games was ideal for trying out various game ideas and mechanics. Since then, I’ve been experimenting with how to make games enjoyable by thinking about mechanisms that haven’t been seen much in previous games and trying to turn them into fun games. This has become my basic process for game development.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.asahi-net.or.jp/~cs8k-cyu/browser.html&quot;&gt;Kenta Cho’s browser games&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;already-youve-mentioned-multiple-programming-languages-in-this-interview-what-factors-do-you-consider-when-selecting-programming-languages-platforms-and-technologies-for-game-development&quot;&gt;Already you’ve mentioned multiple programming languages in this interview. What factors do you consider when selecting programming languages, platforms, and technologies for game development?&lt;/h2&gt;

&lt;p&gt;I flexibly switch programming languages depending on the target device for the game. For the &lt;em&gt;PC-6001&lt;/em&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/MSX&quot;&gt;&lt;em&gt;MSX&lt;/em&gt;&lt;/a&gt;, &lt;em&gt;Z-80&lt;/em&gt; assembler; for &lt;em&gt;PC-9801&lt;/em&gt;, &lt;em&gt;Borland&lt;/em&gt;’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Turbo_C&quot;&gt;&lt;em&gt;Turbo C&lt;/em&gt;&lt;/a&gt;; for &lt;em&gt;Windows&lt;/em&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Delphi_(software)&quot;&gt;&lt;em&gt;Delphi&lt;/em&gt;&lt;/a&gt; or &lt;em&gt;GCC&lt;/em&gt;; for &lt;em&gt;XNA&lt;/em&gt;, &lt;em&gt;C#&lt;/em&gt;; for browsers, &lt;em&gt;ActionScript3&lt;/em&gt; or &lt;em&gt;JavaScript&lt;/em&gt;, and so on.&lt;/p&gt;

&lt;p&gt;But I don’t just use commonly used programming languages; I also look for languages that are easier to use and equipped with new technologies. For example, the &lt;a href=&quot;https://en.wikipedia.org/wiki/D_(programming_language)&quot;&gt;&lt;em&gt;D language&lt;/em&gt;&lt;/a&gt; as a replacement for &lt;em&gt;C&lt;/em&gt;, offering object orientation without the complexity of &lt;em&gt;C++&lt;/em&gt; and faster build speed; &lt;a href=&quot;https://en.wikipedia.org/wiki/Haxe&quot;&gt;&lt;em&gt;Haxe&lt;/em&gt;&lt;/a&gt;, superior to &lt;em&gt;ActionScript3&lt;/em&gt; with features like &lt;a href=&quot;https://en.wikipedia.org/wiki/Mixin&quot;&gt;Mixins&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Enumerated_type&quot;&gt;Enums&lt;/a&gt;; &lt;a href=&quot;https://en.wikipedia.org/wiki/TypeScript&quot;&gt;&lt;em&gt;TypeScript&lt;/em&gt;&lt;/a&gt; for type-checking &lt;em&gt;JavaScript&lt;/em&gt;, allowing proper error detection and code recommendations. I actively use them even if they are slightly less mature or have weaker ecosystems than traditional languages if they can improve development speed.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;i-really-appreciate-how-technology-agnostic-you-are-its-noticeable-that-the-game-is-the-number-one-priority-and-the-choice-of-technologies-is-not-so-important-this-is-similar-to-how-i-work-in-that-im-happiest-when-the-technologies-fade-away-and-i-can-concentrate-on-the-game-design-and-implementation-details-could-you-tell-us-more-about-your-approach-to-game-development&quot;&gt;I really appreciate how technology agnostic you are. It’s noticeable that the game is the number one priority and the choice of technologies is not so important. This is similar to how I work, in that I’m happiest when the technologies fade away and I can concentrate on the game design and implementation details. Could you tell us more about your approach to game development?&lt;/h2&gt;

&lt;p&gt;As I mentioned earlier, I think about game mechanisms that haven’t been seen in previous games. However, it’s challenging to conceive completely new mechanisms. Instead, I often borrow and arrange parts of mechanisms from old arcade games or submission magazines like “Mycom BASIC Magazine”. Old games focused more on the novelty of rules and mechanics than on content like scenarios, which is very informative for game development.&lt;/p&gt;

&lt;p&gt;I also create games driven by specific technologies. I’ve incorporated procedural content generation and physics calculations into shooting games. Before &lt;em&gt;Windows&lt;/em&gt;, I implemented 3D drawing logic and software-based screen rotation, scaling, and shrinking. Recently, I’ve been experimenting with whether everything from game idea conception to programming can be procedurally generated.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;im-also-interested-in-this-aspect-of-game-development-its-a-deep-well-with-a-lot-of-opportunity-i-can-see-its-influence-in-many-of-the-games-youve-created-using-your-crisp-game-lib-what-was-the-thinking-behind-your-framework&quot;&gt;I’m also interested in this aspect of game development, it’s a deep well with a lot of opportunity. I can see its influence in many of the games you’ve created using your &lt;em&gt;Crisp Game Lib&lt;/em&gt;. What was the thinking behind your framework?&lt;/h2&gt;

&lt;p&gt;The goal of &lt;a href=&quot;https://github.com/abagames/crisp-game-lib&quot;&gt;&lt;em&gt;Crisp Game Lib&lt;/em&gt;&lt;/a&gt; is to enable the creation of innovative games within a three-hour timeframe. For this, I made it easy to implement collision detection, which is typically challenging. I particularly focused on making collision detection easy for geometric shapes like lines and arcs, allowing the inclusion of geometric shapes as terrain, obstacles, players, and enemies. This makes it easier to create games different from traditional sprite-based 2D games.&lt;/p&gt;

&lt;p&gt;It also includes features for procedurally generating background music and sound effects. Automatically generated background music and quantized sound effects make it possible to create enjoyable games even within a short development period.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/abagames/crisp-game-lib&quot;&gt;Crisp Game Lib&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.asahi-net.or.jp/~cs8k-cyu/browser.html&quot;&gt;Browser games made using Crisp Game Lib&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;your-recent-games-use-quite-simple-scoring-systems-especially-when-compared-with-arcade-or-pinball-scoring-systems-what-are-your-thoughts-on-scoring&quot;&gt;Your recent games use quite simple scoring systems, especially when compared with arcade or pinball scoring systems. What are your thoughts on scoring?&lt;/h2&gt;

&lt;p&gt;In a simple scoring system, it’s important to reward the player’s risky actions with high scores. Assigning high scores or multipliers for actions like attracting and defeating many enemies at once, narrowly avoiding enemy attacks, or collecting hard-to-reach items can add depth to the gameplay. Additionally, I make it a point to clearly display the acquired score and multipliers on the screen, making it easy for players to understand how to earn high scores.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-gameplay-concepts-in-your-recent-games-are-also-beautiful-in-their-simplicity-but-at-the-same-time-they-have-depth-how-do-you-approach-the-difficulty-curve-to-ensure-your-game-is-enjoyable-for-as-many-people-as-possible&quot;&gt;The gameplay concepts in your recent games are also beautiful in their simplicity, but at the same time they have depth. How do you approach the difficulty curve to ensure your game is enjoyable for as many people as possible?&lt;/h2&gt;

&lt;p&gt;I often use the traditional Game &amp;amp; Watch era mechanic of increasing difficulty as time goes on from the start of the game. In such cases, I consciously choose between a linearly increasing difficulty (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;difficulty = time&lt;/code&gt;) and one that gradually becomes milder, using the square root function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;difficulty = sqrt(time)&lt;/code&gt;). Linear is usually fine, but for parameters like enemy size, which could become unreasonably difficult if too large, I use square root to maintain game balance over time.&lt;/p&gt;

&lt;p&gt;As mentioned in the previous answer, rewarding risky actions is closely related to appropriate difficulty settings. Increasing difficulty over time means to achieve high scores, players need to take risky actions and score high from the early, easier parts of the game. This avoids boredom in the early stages, making the game enjoyable from the start.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-january-2024-your-game-paku-paku-went-viral-after-being-featured-on-hacker-news-it-was-picked-up-by-various-bloggers-and-news-outlets-and-was-even-ported-by-fans-to-multiple-systems-were-you-surprised-by-this-turn-of-events-and-why-do-you-think-the-game-garnered-such-attention&quot;&gt;In January 2024, your game &lt;em&gt;Paku Paku&lt;/em&gt; went viral after being featured on &lt;em&gt;Hacker News&lt;/em&gt;. It was picked up by various bloggers and news outlets, and was even ported by fans to multiple systems. Were you surprised by this turn of events, and why do you think the game garnered such attention?&lt;/h2&gt;

&lt;p&gt;When I released &lt;a href=&quot;https://abagames.github.io/crisp-game-lib-11-games/?pakupaku&quot;&gt;&lt;em&gt;Paku Paku&lt;/em&gt;&lt;/a&gt; a year ago, it was fairly well-received among Japanese players, but I was surprised that it gained attention from international players a year later. Many articles described &lt;em&gt;Paku Paku&lt;/em&gt; as a ‘&lt;em&gt;1D Pac-Man&lt;/em&gt;’, which likely sparked curiosity about how a 1D version of &lt;em&gt;Pac-Man&lt;/em&gt; could be realized. &lt;em&gt;Paku Paku&lt;/em&gt; was an example of the demakes and minimalization I often do when making small games. Successfully balancing it as a good game within the strong constraint of 1D might be why it became popular. My experiences with games I made and played during the pocket computer era were very helpful in developing a 1D game.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://abagames.github.io/crisp-game-lib-11-games/?pakupaku&quot;&gt;Play Paku Paku in your browser&lt;/a&gt; “…just one more go…”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;paku-paku-could-be-considered-the-essence-of-kenta-cho-from-the-single-line-display-pocket-computers-through-namcos-arcade-titles-like-pac-man-to-his-love-for-modern-programming-languages-and-the-web-browser-as-a-platform&quot;&gt;&lt;em&gt;Paku Paku&lt;/em&gt; could be considered the essence of Kenta Cho: from the single-line display pocket computers, through &lt;em&gt;Namco&lt;/em&gt;’s arcade titles like &lt;em&gt;Pac-Man&lt;/em&gt;, to his love for modern programming languages and the web browser as a platform.&lt;/h2&gt;

&lt;h2 id=&quot;many-thanks-to-kenta-cho-for-this-interview-now-go-play-some-of-his-games&quot;&gt;Many thanks to Kenta Cho for this interview. Now go play some of his games!&lt;/h2&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 10 Feb 2024 21:46:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2024/02/10/interview-kenta-cho-indie-game-developer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2024/02/10/interview-kenta-cho-indie-game-developer/</guid>
        </item>
      
    
      
        <item>
          <title>See the sky: Thoru Yamamoto’s Christmas story, for Playdate</title>
          <description>&lt;p&gt;&lt;em&gt;Thoru Yamamoto&lt;/em&gt; (Japanese: 山本徹 or とーるやまもと), born 1955, is a Japanese multimedia artist. Over the years he has released work in many formats including, but not limited to: magazine illustrations, HyperCard decks, interactive CD-ROMs, printed books, websites, digital stickers, and videos. He is perhaps best known for his story books distributed as HyperCard stacks and his unique 1-bit art taking advantage of the limitation imposed by early Apple Macintosh computers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See the sky&lt;/em&gt; is one such story book, a Christmas present released in October 1992 as a series of HyperCard stacks. In 1996 it was re-released in a remastered form: as an interactive CD-ROM, produced using Macromedia Director, which added ambient music and navigation to the original images. Also released in 1996 was &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1582466068517310465&quot;&gt;a printed book of the story, presented as 3 images per page&lt;/a&gt;. Finally, in 1999 a CD-R of the combined HyperCard stacks was released.&lt;/p&gt;

&lt;h2 id=&quot;a-new-edition-for-2023&quot;&gt;A new edition for 2023&lt;/h2&gt;

&lt;p&gt;I’ve created a new version of &lt;em&gt;See the sky&lt;/em&gt; for &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt;. The remastering/remaking/porting process was quite involved, so I’d like to detail it in this blog post.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/thoru-yamamoto-see-the-sky-playdate.gif#playdate&quot; alt=&quot;See the sky&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;extracting-the-original-images&quot;&gt;Extracting the original images&lt;/h2&gt;

&lt;p&gt;I used &lt;a href=&quot;https://github.com/PierreLorenzi/HyperCardPreview&quot;&gt;HyperCardPreview&lt;/a&gt; to export the assets from the original &lt;a href=&quot;https://en.wikipedia.org/wiki/HyperCard&quot;&gt;HyperCard&lt;/a&gt; stack. I did this back in October 2022, and had to use an old MacBook Pro running Mojave to do it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Just today, whilst writing this blog post, I figured out that HyperCardPreview will refuse to open stacks if the app Stacksmith is also present on your Mac!? As soon as I deleted Stacksmith, HyperCardPreview opened the files just fine. It seems to be some sort of issue with them competing for control of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.apple.hypercard.stack&lt;/code&gt; uti. Weird.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyway, &lt;em&gt;See the sky&lt;/em&gt; consists of just over 500 full screen card images. For other stacks, you might get a combination of background images and card images that would need re-compositing - it really depends on the stack.&lt;/p&gt;

&lt;p&gt;Thoru told me that when he first started out with HyperCard he wasn’t aware of the benefits of using a common background card and different foreground cards, which is why &lt;em&gt;See the sky&lt;/em&gt; consists of only foreground cards. For this reason it was very difficult for him to upload the files, which were rather large for the time. Later productions would make more effective use of background cards to keep the file size as small as possible.&lt;/p&gt;

&lt;h2 id=&quot;implementing-a-viewer&quot;&gt;Implementing a viewer&lt;/h2&gt;

&lt;p&gt;My way of developing is to think of the goal as clearly as possible, then get something up and working as quickly as possible, and after that iterate and refine until I reach the goal. So it was easy to create a sort of slideshow viewer for the images, keeping track of the current image and allowing navigation forwards and backwards with A and B buttons, loading the next/previous image as required. Pretty quickly it became apparent that I could not simply display each screen centred as important content would frequently be out of view.&lt;/p&gt;

&lt;h2 id=&quot;adjusting-each-screen&quot;&gt;Adjusting each screen&lt;/h2&gt;

&lt;p&gt;So I added a table to store offsets for each screen. But defining these manually would be very time consuming so I set about creating an interactive way to do this. I added a debug mode in which I map the d-pad (cursor keys) to move the current image up/down/left/right, along with the ability to save the offsets table to a file. This was a huge productivity boost! But I was still finding it quite a repetitive task, so I added further key mappings so I could use the numbers on the numeric pad of my keyboard to quickly set the offsets for a screen to each of the 8 compass directions, or centred. This increased productivity even more. At this point I found myself setting the same offsets for a screen as the previous screen, so I added to more keys to copy the offset from the previous/following screen. All in all this made setting offsets for 500 screens quick and easy. When I was happy I copied the offset table into the code and that became the default values.&lt;/p&gt;

&lt;p&gt;This is all to say that whilst the original Macintosh resolution of 512×342 does not match the Playdate’s resolution of 400×240, &lt;em&gt;See the sky&lt;/em&gt; still works on Playdate because every screen has been manually repositioned to keep the important elements in view, a process similar to the “pan and scan” adaptation of movies for 4:3 TVs.&lt;/p&gt;

&lt;h2 id=&quot;hypercard-look-and-feel&quot;&gt;HyperCard look and feel&lt;/h2&gt;

&lt;p&gt;The most recognisable feature of many HyperCard stacks are the crossfades between screens. This was essential to the experience. Thoru even took advantage of the crossfade in certain scenes by changing only small elements from screen to screen so that the crossfade turned into a sort of stop-motion animation effect.&lt;/p&gt;

&lt;p&gt;To achieve the crossfade on Playdate I do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Before the transition I capture the current screen using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;playdate.graphics.getWorkingImage()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Next I make this image into an overlay, in my case I’m assigning it to a “fade” sprite&lt;/li&gt;
  &lt;li&gt;Behind the fade image/sprite I load in the requested next/previous image&lt;/li&gt;
  &lt;li&gt;Finally I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;playdate.graphics.image:fadedImage(alpha, Bayer8x8)&lt;/code&gt; to fade out the overlay, which happens over several frames and results in the image becoming more and more transparent, eventually disappearing completely&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the crossfade is simply one image fading away and the image behind it slowly being revealed. Magic.&lt;/p&gt;

&lt;p&gt;I also added the ability to have slower or faster crossfades depending on your preference. I do this by adjusting the refresh/frame rate of the game itself, rather than skipping any of the fade.&lt;/p&gt;

&lt;p&gt;The only other feature I needed to add was a flashing capability. This happens at a handful of places in the story to various degrees, mostly there are a few flashes in places but in one places there are 10 flashes. Given that people with photosensitive epilepsy won’t want to see the screen flash I honour the Playdate “reduce flashing” system setting. If the user has that toggled on the story will only flash once at each instance. The speed of the flashing is quite slow, and not tied to the speed of the crossfade.&lt;/p&gt;

&lt;p&gt;Page turn sounds are recordings of the sounds defined in the original HyperCard stack, another essential part of the experience. Thoru describes these sounds as “pipo papo” and that’s how I label it in the settings. I also provide the option to use a more realistic page turn sound, or switch off page turn sounds entirely.&lt;/p&gt;

&lt;h2 id=&quot;chapters&quot;&gt;Chapters&lt;/h2&gt;

&lt;p&gt;I added chapter navigation which unlocks as you go through the story, in a similar way to the 1996 CD-ROM release of &lt;em&gt;See the sky&lt;/em&gt;. This means you can revisit any previous chapter, and once you’ve reached the end of the story you’ll have access to all chapters. If you want to reset that progress, for example to let somebody else enjoy the story from the beginning and remove any temptation for them to skip ahead, you can delete the “game data” through Playdate Settings. Chapter title cards are only shown when using the chapter navigation, and not whilst going through the story, I do this by injecting temporary images into the crossfade system.&lt;/p&gt;

&lt;h2 id=&quot;progress&quot;&gt;Progress&lt;/h2&gt;

&lt;p&gt;I also added a progress bar, shown when you bring up the menu. It’s a vertical bar drawn in the centre of the screen between the menu and faded game image. The bar itself is dithered at 50%, and onto it I draw white markers for each chapter position. The current position is shown by drawing a solid white bar from the bottom of the screen to the current position. This means that the bar “fills” with white from the bottom as you progress through the story.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/thoru-yamamoto-see-the-sky-playdate.png#playdate&quot; alt=&quot;Progress bar&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;experiments-with-sound&quot;&gt;Experiments with sound&lt;/h2&gt;

&lt;p&gt;The 1996 CD-ROM release of &lt;em&gt;See the sky&lt;/em&gt; has ambient music, but Thoru and myself couldn’t figure out the rights to this so it could not be used. I had done the work, just in case, so I’ll mention it here.&lt;/p&gt;

&lt;p&gt;I &lt;a href=&quot;/2023/08/12/extracting-sounds-from-macromedia-director-files/&quot;&gt;extracted the audio from the Director files using a technique I’ve previously blogged about&lt;/a&gt;. I then converted the audio files to 44.1KHz 16-bit WAV files, and used &lt;a href=&quot;https://www.ocenaudio.com/en/startpage&quot;&gt;Ocen Audio&lt;/a&gt; to remove the base noise from those files. Basically, you select a part of the audio that contains only noise and it removes this from the entire audio file. Doing this without first upsampling the audio meant it did not work as well or at all. After the de-noising, I converted to ADPCM using adpcm-xq which gave files half the original size at higher quality and with lower noise levels.&lt;/p&gt;

&lt;h2 id=&quot;experiments-with-music&quot;&gt;Experiments with music&lt;/h2&gt;

&lt;p&gt;After we realised we would not be able to use the ambient music, I looked at using completely different music, turning to the catalogue of watson @ MusMus. I found a piece of music for each chapter of the story and extracted loops using PyMusicLooper. I then tweaked the loops by adjusting their start point by moving a section of audio from one end to the other so the loop began with the part of the audio I thought sounded best. I use &lt;a href=&quot;https://twistedwave.com&quot;&gt;TwistedWave&lt;/a&gt; for most sound editing like this. Thoru really liked the music itself but was of the opinion that no music would be more honest to the original release. I can’t argue with that reasoning. Feel free to play your own choice of music whilst experiencing the story.&lt;/p&gt;

&lt;h2 id=&quot;optimising-for-size&quot;&gt;Optimising for size&lt;/h2&gt;

&lt;p&gt;The final app binary is tiny but the images are adding up to about 3MB. That’s fine, but I wondered how I might be able to optimise them. I used imagemagick’s montage command to stitch the images together into a grid. In Playdate land we call this an image table, but you might refer to it as a sprite sheet. This reduced the size of 500 separate card images from 3MB to a single image of just 2MB. A nice saving!&lt;/p&gt;

&lt;p&gt;The 500 screen image table occupies 10.5MB RAM, so about two thirds of the available RAM on Playdate. Side-effects of bundling 500 screens as single file are a short delay on loading for users, a short delay on building for me as a developer, and the need to regenerate the single image if any of the images it contains are changed.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;At this point, I could have stopped. I should have stopped. But, of course, I didn’t.&lt;/p&gt;

  &lt;p&gt;I’ve often wondered how the dimensions of a sprite sheet grid affect the file size when saved as a compressed format such as PNG. The extreme examples in this case would be having a tall grid of 1×504 or a wide grid of 504×1, and in between we have some exact multiples. I generated one sprite sheet for each grid size and here found that for this set of images a grid of 42×12 resulted in the smallest image file size a saving of a further 4% or so. The savings are similar when converted to the Playdate pdt image format. Note that this sort of optimisation only works for solid images, not for images with any alpha/transparency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that’s it. The final size of this new version is smaller than the original, mostly due to the image optimisation. I could make it even smaller by exporting all the final crops of the screen images, create a new image table of those, displaying them with zero offset. But I decided to not go there!&lt;/p&gt;

&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;

&lt;p&gt;You can download &lt;em&gt;See the sky&lt;/em&gt; for Playdate from my page on itch.io, and it is a free download. A present from Thoru and myself. With best wishes for a Merry Christmas.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gingerbeardman.itch.io/see-the-sky&quot;&gt;gingerbeardman.itch.io/see-the-sky&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;500 screens&lt;/li&gt;
  &lt;li&gt;10 chapters&lt;/li&gt;
  &lt;li&gt;~ 1 hour experience&lt;/li&gt;
  &lt;li&gt;Quick navigation menu unlocked as you go&lt;/li&gt;
  &lt;li&gt;Position is remembered between launches&lt;/li&gt;
  &lt;li&gt;Settings for sound and crossfade speed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;credits&quot;&gt;Credits&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Created by Thoru Yamamoto&lt;/li&gt;
  &lt;li&gt;Edited by Matt Sephton&lt;/li&gt;
  &lt;li&gt;© 1992 Thoru Yamamoto&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://lostmediawiki.com/Thoru_Yamamoto_works_(partially_found_interactive_media;_1990s)&quot;&gt;Thoru Yamamoto @ Lost Media Wiki&lt;/a&gt; read more about his work&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/thoru-yamamoto-hypercard-stacks&quot;&gt;Thoru Yamamoto HyperCard Stacks Collection @ archive.org&lt;/a&gt; view the original &lt;em&gt;See the sky&lt;/em&gt; &amp;amp; more&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;birthday-blog-post&quot;&gt;Birthday blog post?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Check out my other &lt;a href=&quot;/tag/birthday/&quot;&gt;#birthday&lt;/a&gt; blog posts.&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 16 Dec 2023 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/12/16/see-the-sky-thoru-yamamoto-christmas-story-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/12/16/see-the-sky-thoru-yamamoto-christmas-story-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Dynamic music and sound techniques for video games</title>
          <description>&lt;p&gt;The only aspect of game development I’ve not attempted myself is the music. I mostly use royalty free music of Japanese origin (just because I dig their vibe, man) as in the case of &lt;a href=&quot;https://soundcloud.com/mac-vogelsang/sets/sparrow-solitaire&quot;&gt;&lt;em&gt;Sparrow Solitaire&lt;/em&gt;&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1732555533863751691&quot;&gt;&lt;em&gt;Fore! Track&lt;/em&gt;&lt;/a&gt; or in rare cases I pay friends (like the amazing Jamie Hamshere) to write music specifically for a game as in the case of &lt;a href=&quot;https://soundcloud.com/gingerbeardman/sets/yoyozo-soundtrack&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt;&lt;/a&gt;. Maybe one day that will change, but until then I’m enjoying gaining more understanding and control of the music in my games. Whilst I develop games for &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; these techniques are general enough to apply anywhere.&lt;/p&gt;

&lt;p&gt;The main way I make the music into more than a static track is to apply a dynamic, reactive, or adaptive effect in one way or another. In this blog post I’ll go into how I’ve achieved this. Please note this is by no means an exhaustive list, rather it’s just the ones I have personally used.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;dynamic-bpm&quot;&gt;Dynamic BPM&lt;/h2&gt;

&lt;p&gt;I use this method in &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt;&lt;/a&gt; because it uses “chip tune” music data representing songs composed by my friend Jamie Hamshere using &lt;a href=&quot;https://play.date/pulp/&quot;&gt;&lt;em&gt;Playdate Pulp&lt;/em&gt;&lt;/a&gt;. A playback engine for this data, written by Pulp creator Shaun Inman, works beautifully when integrated into games written using Lua and the &lt;a href=&quot;https://play.date/dev/&quot;&gt;&lt;em&gt;Playdate SDK&lt;/em&gt;&lt;/a&gt;. I added hook to allow me to set the BPM at any point to any value. The end result is that the BPM of the music scales from 130 to 135 as your score increases. As you improve at the game you’ll notice the music speed up ever so slightly along with an increase in tension and anxiety.&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;140&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allow=&quot;autoplay&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1685873466&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true&amp;amp;visual=true&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Of course, it’s possible to do this in a pre-recorded song stored as a digital music file, but it’s much more difficult for that to respond to the what the player does in the game. An example that takes an interesting approach to this is the track &lt;a href=&quot;https://www.youtube.com/watch?v=1_iZh_2li4M&quot;&gt;“Sunny Day” from the game Vib Ribbon&lt;/a&gt;, and indeed the rest of its soundtrack, where tempo changes over the duration of each song.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;infinite-variations&quot;&gt;Infinite Variations&lt;/h2&gt;

&lt;p&gt;Another technique I use in &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt;&lt;/a&gt;, again made possible because I can modify the music data and playback parameters in real time. With this one I cycle the values for the instrument voices pseudo-randomly so that the track plays once as it was programmed and then morphs slightly for each subsequent playback. The track is quite minimal and repetitive in &lt;a href=&quot;https://sites.barbican.org.uk/reichglassadams/&quot;&gt;Steve Reich, Philip Glass or John Adams&lt;/a&gt; sort of way, so there are automated variations wandering around the original arrangement work really well. Perhaps the &lt;a href=&quot;https://www.youtube.com/watch?v=NkBXgcN3fXo&quot;&gt;ultimate implementation of this approach is &lt;em&gt;Wii Play’s&lt;/em&gt; Tanks game&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;140&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allow=&quot;autoplay&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1685873439&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true&amp;amp;visual=true&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;For sound effects, I vary the playback sample rate to change the pitch of sound effects. This prevents the same sound effect becoming monotonous. Two examples might be &lt;em&gt;Lara Croft&lt;/em&gt; in the first &lt;em&gt;Tomb Raider&lt;/em&gt; game, &lt;a href=&quot;https://youtu.be/Roi2UelYGsU?si=_17TmHon5JenRxCM&amp;amp;t=1079&quot;&gt;groaning the same way every time she climbs up a platform&lt;/a&gt; compared with &lt;a href=&quot;https://www.youtube.com/watch?v=JGQeQmUuMas&quot;&gt;the rich variety of sounds when &lt;em&gt;Mario&lt;/em&gt; walks on different surfaces&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;blendingfadingbalance&quot;&gt;Blending/Fading/Balance&lt;/h2&gt;

&lt;p&gt;Another idea I had was to fade or blend two tracks as the player makes progress in the game. But how to find two tracks that can be cross-faded in a way that always makes sense? Of course you can have them composed, but what about in music that already exists? If only there was an easy way to find such tracks!&lt;/p&gt;

&lt;p&gt;There is: stereo pairs! You’d be surprised at how different the left and right channels can sound whilst obviously being the same tune. Of course this means that are output audio will be mono but for me on Playdate that’s just fine. I use this method in &lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;&lt;em&gt;Fore! Track&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is to adjust the balance of the two parts of the audio, at once point you’re playing just the left audio across both outputs, then you adjust the balance to play a mix of both, at the other end of the scale you’d be playing just the right audio. Unfortunately the Playdate SDK currently has no API to easily adjust balance, so I had to program a method myself. First, I convert to the destination format which is for me ADPCM using &lt;a href=&quot;https://github.com/dbry/adpcm-xq&quot;&gt;adpcm-xq&lt;/a&gt;. Once the files are in this format I split the stereo pair into two files, one for the left channel and one for the right channel. Converting to the destination format before splitting ensures that the two are exactly the same length in terms of samples/bytes.&lt;/p&gt;

&lt;p&gt;In the game I fade between the two as the score/chain increases, which has the effect of subtly changing the instrumentation of the tune. It’s one of those things that most people wouldn’t notice, but that once you know about it you can’t miss it. Sadly, I don’t have an easy way to demo this in a video or sound file.&lt;/p&gt;

&lt;p&gt;For sound effects, you might consider panning to increase immersion and guide the players visual focus through use of audio. In &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt;&lt;/a&gt; I pan certain sounds relative to the location of the ball, certain other sounds relative to the location of the player, and there are global sound effects that are not panned at all.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-teaser.gif#playdate&quot; alt=&quot;YOYOZO&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;progressive-loops&quot;&gt;Progressive Loops&lt;/h2&gt;

&lt;p&gt;Digital audio is a different beast. I always try to find a time that fits the game, going so far as to audition many hundreds of tracks and creating playlist of songs far ahead of ever making a game or even having and idea for a game. I try to find tracks that will loop well and not get annoying, which is easier said than done. If I can’t find a track that loops well, there’s another way.&lt;/p&gt;

&lt;p&gt;You can use &lt;a href=&quot;https://github.com/arkrow/PyMusicLooper&quot;&gt;PyMusicLooper&lt;/a&gt; to analyse a digital audio track and spit out information about ranges that loop nicely, along with a percentage indicating how good it considers the loop. In other words you can identify and extract a loop from digital audio files that sound like they could loop. Of course, can’t identify loops in tracks that aren’t repetitive or consistent in their structure.  You might get PyMusicLooper to split the file into into three sections (intro, loop, outro) or just export the loop information as a text file to use in your game. Which I choose depends on how much of the file I want to use.&lt;/p&gt;

&lt;p&gt;For an example, in my game &lt;a href=&quot;https://play.date/games/icarus&quot;&gt;Super ICARUS&lt;/a&gt; I’m using a file that gives the vibe I wanted in the game and sounded like it contained some loops even though it was not provided as a looping song. PyMusicLooper reported that it contains tens of possible loops of varying quality.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;loop&lt;/th&gt;
      &lt;th&gt;start&lt;/th&gt;
      &lt;th&gt;end&lt;/th&gt;
      &lt;th&gt;duration&lt;/th&gt;
      &lt;th&gt;match&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;3.437&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;30.755&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;27.318&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;94.87%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;0.023&lt;/td&gt;
      &lt;td&gt;27.341&lt;/td&gt;
      &lt;td&gt;27.318&lt;/td&gt;
      &lt;td&gt;94.79%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;7.279&lt;/td&gt;
      &lt;td&gt;34.598&lt;/td&gt;
      &lt;td&gt;27.319&lt;/td&gt;
      &lt;td&gt;94.63%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;6.850&lt;/td&gt;
      &lt;td&gt;34.168&lt;/td&gt;
      &lt;td&gt;27.318&lt;/td&gt;
      &lt;td&gt;93.95%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;8.127&lt;/td&gt;
      &lt;td&gt;35.445&lt;/td&gt;
      &lt;td&gt;27.318&lt;/td&gt;
      &lt;td&gt;93.92%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;22.221&lt;/td&gt;
      &lt;td&gt;52.953&lt;/td&gt;
      &lt;td&gt;30.732&lt;/td&gt;
      &lt;td&gt;93.80%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;6&lt;/td&gt;
      &lt;td&gt;25.635&lt;/td&gt;
      &lt;td&gt;56.366&lt;/td&gt;
      &lt;td&gt;30.731&lt;/td&gt;
      &lt;td&gt;93.23%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;7&lt;/td&gt;
      &lt;td&gt;11.970&lt;/td&gt;
      &lt;td&gt;39.288&lt;/td&gt;
      &lt;td&gt;27.318&lt;/td&gt;
      &lt;td&gt;93.17%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;8&lt;/td&gt;
      &lt;td&gt;6.850&lt;/td&gt;
      &lt;td&gt;35.875&lt;/td&gt;
      &lt;td&gt;29.025&lt;/td&gt;
      &lt;td&gt;92.13%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;6.850&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;54.660&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;47.810&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;91.98%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;20.515&lt;/td&gt;
      &lt;td&gt;52.953&lt;/td&gt;
      &lt;td&gt;32.438&lt;/td&gt;
      &lt;td&gt;91.54%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;10.263&lt;/td&gt;
      &lt;td&gt;37.581&lt;/td&gt;
      &lt;td&gt;27.318&lt;/td&gt;
      &lt;td&gt;91.26%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;12&lt;/td&gt;
      &lt;td&gt;22.221&lt;/td&gt;
      &lt;td&gt;54.660&lt;/td&gt;
      &lt;td&gt;32.439&lt;/td&gt;
      &lt;td&gt;91.11%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;23.928&lt;/td&gt;
      &lt;td&gt;68.325&lt;/td&gt;
      &lt;td&gt;44.397&lt;/td&gt;
      &lt;td&gt;90.92%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;39.300&lt;/td&gt;
      &lt;td&gt;70.031&lt;/td&gt;
      &lt;td&gt;30.731&lt;/td&gt;
      &lt;td&gt;90.82%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;12.399&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;70.449&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;58.050&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;90.78%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;My goal was to find three loops of increasing length and with a high percentage loop quality. After some experimentation and listening, I decided on loops 0, 9, and 15 (table only shows the top 15 loops from this track, even though their percentage loop match are not 100% they still sound like good loops, so selecting these loops was a case of finding three of suitable length and content. PyMusicLooper will let you audition the loops directly, so there’s no need to use an audio editor.&lt;/p&gt;

&lt;p&gt;Using the Playdate SDK I can do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setRange()&lt;/code&gt; on the audio track to change the playback range and the music will loop between those new points when the playhead reaches the end of the range. For this reason, this method does not provide immediate results so is better used to signify a large change in progress as the delay until the change is noticed will be an unknown amount of time. But when the change does kick in it’s a really nice surprise!&lt;/p&gt;

&lt;p&gt;The final result sees the game start by playing loop 1 (synth and drums) and then as the player gets makes some good progress I switch to loop 2 (synth, drums, guitar licks), and finally as they pass a certain threshold I switch to loop 3 (synth, drums, guitar licks into guitar solo). This provides music that sounds very dynamic with little effort. You could even drop back to the shorter loops if the player lost a life, missed a target, and so on. Again, there’s no real way of me demoing this as it’s something that will become apparent through play, and the final result is just one long dynamic song!&lt;/p&gt;

&lt;p&gt;For sound effects I use the same approach as above. As an example, in &lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;&lt;em&gt;Fore! Track&lt;/em&gt;&lt;/a&gt; there is a clapping sound effect after the player gets the ball in a hole. This is a long sound effect but I play three increasingly long sections of it as the player’s chain increases (number of successive holes-in-one). It starts off as a short clap, increases to a longer more enthusiastic clap, and finally it begins with a whoop and continues to enthusiastic clap. I have a separate sound effect for the end game cheer that plays over the top of the full clap, resulting in a raucous end of game celebration.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;quantised-sounds&quot;&gt;Quantised Sounds&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&quot;https://play.date/games/icarus&quot;&gt;Super ICARUS&lt;/a&gt; created certain game event sounds from small sections of the music track. I then adjust playback rate/speed/pitch. The result is that the sounds appear to be quantised or matched to the music. I’m not sure how to describe this phenomenon accurately in musical/technical terms.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I’d love to hear about other methods of achieving dynamic music and sound in video games. Feel free to reach out to me on social media!&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt; (or, how I made a Playdate game in 39KiB)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/11/26/easter-egg-emoji-converting-pixels-into-particles/&quot;&gt;Easter egg emoji: converting pixels into particles&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/&quot;&gt;Dynamic music and sound techniques for video games&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;elsewhere&quot;&gt;Elsewhere&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;2023-11-22—&lt;a href=&quot;https://news.ycombinator.com/item?id=38584336&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-22—&lt;a href=&quot;https://tildes.net/~games/1crg/dynamic_music_and_sound_techniques_for_video_games&quot;&gt;Tildes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 09 Dec 2023 01:22:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/</guid>
        </item>
      
    
      
        <item>
          <title>Easter egg emoji: converting pixels into particles</title>
          <description>&lt;p&gt;I’m &lt;a href=&quot;/2019/08/14/moai-games/&quot;&gt;fascinated with Moai&lt;/a&gt; so I always try to squeeze an appearance into my games. Moai in video games is a meme, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Easter_egg_(media)&quot;&gt;easter egg&lt;/a&gt;, going all the way back to 1983. But my game YOYOZO (&lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;out now for the Playdate handheld&lt;/a&gt;) is about capturing stars in space using a yoyo, so how could I get a Moai in it?&lt;/p&gt;

&lt;p&gt;The source of my inspiration was a trip to Japan back in 2004 (my only one, so far). Visiting in August meant that one of the things we did was go to an &lt;a href=&quot;https://www.japan-guide.com/e/e2267.html&quot;&gt;annual hanabi fireworks festival&lt;/a&gt;, where I saw &lt;a href=&quot;https://blog.gaijinpot.com/four-types-of-japanese-fireworks/&quot;&gt;katamono&lt;/a&gt; for the first time. These are fireworks that explode in the shapes of drawings, like a smiley face or a magic 8-ball. I was amazed and the experience has stuck with me for over 20 years. Maybe I could add Moai into YOYOZO by making the explosions appear like the katamono?&lt;/p&gt;

&lt;p&gt;I started off by coding the patterns by hand, as a test, but my calculations weren’t precise enough and the whole endeavour quickly grew too complicated to manage by hand. I needed a better, more automated way. The method that I arrived at is what I’ll document in this post.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;pixels-as-code&quot;&gt;Pixels as code&lt;/h2&gt;

&lt;p&gt;Instead of plotting values by hand in code I figured that it would make more sense if I could draw the patterns and then somehow convert them into coordinates. I use &lt;a href=&quot;/2023/05/10/piskel-for-playdate/&quot;&gt;Piskel&lt;/a&gt; as my Playdate-centric graphics editor. It’s a really useful tool. So I drew a few emoji-like patterns, keeping in mind that they would be converted into a cluster of points and exploded from an origin. This took a bit of experimentation but I ended up with a sort of already exploded look.&lt;/p&gt;

&lt;p class=&quot;screen&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-emoji.png#pixel&quot; alt=&quot;EMOJI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To get the pixel data out of Piskel in text form I make use of its “export as a C file” feature. This results in code definitions similar to the below. (I use a script that does some simple regex search/replace to reformat these definitions to be a little more succinct and readable in my Lua code.)&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define EMOJI-TABLE-11-11_FRAME_COUNT 3
#define EMOJI-TABLE-11-11_FRAME_WIDTH 11
#define EMOJI-TABLE-11-11_FRAME_HEIGHT 11
&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* Piskel data for &quot;emoji-table-11-11&quot; */&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;121&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;pixels-as-points&quot;&gt;Pixels as points&lt;/h2&gt;

&lt;p&gt;With this data in hand, my plan was to convert them into points expressed as an angle and distance from an origin. This way of expressing points is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Polar_coordinate_system&quot;&gt;polar coordinate system&lt;/a&gt; so there was no need to invent anything, I just needed to code a function that would take a grid of pixels expressed as &lt;em&gt;(x, y)&lt;/em&gt; and convert them to a series of distances and angles expressed as &lt;em&gt;(r, θ)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The way I do this is to read the point data in from a grid of pixels, offsetting that data by half the width and height of the &lt;em&gt;odd-sized&lt;/em&gt; grid so that the centre of the grid &lt;em&gt;(0, 0)&lt;/em&gt; is the middle of the centre pixel. And finally I convert those adjusted &lt;em&gt;(x, y)&lt;/em&gt; values to polar &lt;em&gt;(r, θ)&lt;/em&gt; coordinates. This worked really well!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Below is a work-in-progress GIF captured on 14 September 2023, shortly after getting the feature working. This animation also shows an early version of the HUD and debug values for ball size and the length of the beam.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-emoji.gif#playdate&quot; alt=&quot;EMOJI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The finishing touches (not shown in the above animation) were to add some small amount of &lt;em&gt;pseudo-randomisation&lt;/em&gt; to the initial rotation of the emoji, the initial “colour” of each particle, and changing the coordinates of each point slightly so they appear more organic and move at slightly different speeds. I eventually settled on over a dozen such pixel patterns in the game (how many have you spotted?). Once your score is higher than 50M points every explosion is an emoji! &lt;a href=&quot;https://play.date/games/yoyozo/#gameListingMoreInfo&quot;&gt;Check out the game manual&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;pseudo-random&quot;&gt;Pseudo-random?&lt;/h2&gt;

&lt;p&gt;I try to limit my use math.random values if I can help it, or at least use it in controlled way. I already use that for the positions of the stars, so if I also used it for explosions that would mean it would become far less controlled. Controlling the use of random is important in making a game system deterministic, if you want it to react the same way every time.&lt;/p&gt;

&lt;p&gt;If you’re wondering how you can get pseudo-random values, the main method I use is a trick I learned from the old arcade game &lt;a href=&quot;/2011/10/26/flicky-1984/&quot;&gt;Flicky (1984, SEGA)&lt;/a&gt; which is a game &lt;a href=&quot;https://www.flicky1984.com/post/709058873877790720/just-a-quick-reminder-that-you-can-play-my-flicky&quot;&gt;I own as a physical cabinet&lt;/a&gt;. Anyway, in Flicky there is a diamond that appears under seemingly random conditions.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One of the MAME programmers was kind enough &lt;a href=&quot;https://www.flicky1984.com/post/54534135892/the-best-jewel-thief-in-the-world&quot;&gt;reverse engineer Flicky on my behalf and figured out what makes the diamond appear&lt;/a&gt;. It turns out the diamond will appear only if you knock out an enemy cat and it disappears outside of the centre third of the play area &lt;em&gt;and&lt;/em&gt; if the x coordinate at which the cat finally comes to rest is even. So, about 50% chance &lt;em&gt;but&lt;/em&gt; only if you position the screen correctly during play.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, taking a cue from that wonderful Flicky logic, I use modulus—which returns the remainder of a division—as my main mechanism of generating pseudo-random values. It ensures a value in the range &lt;em&gt;[0,n-1]&lt;/em&gt;. They key thing to note is that if you base it on values in your game system that are constantly changing you can get seemingly random values that have the benefit of being deterministic if the player is skilled enough at repeating their inputs. The deterministic thing is how pretty much all the old school arcade games operated from Pac-Man to Flicky and more.&lt;/p&gt;

&lt;p&gt;Common game variables I use are: game tick (my alternative to timer), x-coordinate, y-coordinate, speed, angle, or combinations of more than one of these. I also used this approach in YOYOZO for the starfield particles, and in &lt;a href=&quot;/2023/04/13/sparrow-solitaire-for-playdate/&quot;&gt;Sparrow Solitaire&lt;/a&gt; for the falling particles that make up the &lt;a href=&quot;https://www.reddit.com/r/PlaydateConsole/comments/12vcrm6/dynamic_weather_effects_and_more_in_the_sparrow/&quot;&gt;weather effects&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;playdate-particles&quot;&gt;Playdate particles&lt;/h2&gt;

&lt;p&gt;There are &lt;a href=&quot;https://github.com/PossiblyAxolotl/pdParticles&quot;&gt;one or more libraries&lt;/a&gt; available that can be used to manage particles in a performant way on Playdate. Though I tend to code my own system that is bespoke to the game I’m working on at the time (I start each game from a blank file and use minimal libraries, force of habit). But the important thing for such limited platforms, especially when using Lua, is to use a pool of particles so that you’re not constantly creating and destroying particles which would wreak havoc on performance through overuse of Lua’a garbage collector.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt; (or, how I made a Playdate game in 39KiB)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/&quot;&gt;Dynamic music and sound techniques for video games&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/yoyozo/#gameListingMoreInfo&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt; manual/player’s guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 26 Nov 2023 20:41:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/11/26/easter-egg-emoji-converting-pixels-into-particles/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/11/26/easter-egg-emoji-converting-pixels-into-particles/</guid>
        </item>
      
    
      
        <item>
          <title>YOYOZO (or, how I made a Playdate game in 39KB)</title>
          <description>&lt;blockquote&gt;
  &lt;p&gt;2023-12-27—&lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;Ars Technica: YOYOZO wins GOTY accolade!&lt;/a&gt; almost unbelievable to be listed alongside such games as: Chants of Sennaar, Cocoon, Dave the Diver, Humanity, The Legend of Zelda: Tears of the Kingdom, Pikmin 4, Puzzmo, Super Mario Bros. Wonder, Venba and Viewfinder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A game I made for the Playdate handheld was released today! &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;Go buy it&lt;/a&gt; and then come back to read this blog post.&lt;/p&gt;

&lt;p&gt;It’s called YOYOZO and in it you control a space yo-yo and have to collect stars in a sort of cosmic ballet. Well, at first it might feel a little like being on a fairground ride, but eventually you’ll become good enough for it to feel like ballet. The concept is based on my memory of a game called &lt;a href=&quot;https://archive.org/details/Pendulumania-v1.3&quot;&gt;Pendulumania&lt;/a&gt; that I played 20 years ago.&lt;/p&gt;

&lt;p&gt;The most amazing thing about this game, for me, is that launch version weighs in at a file size of &lt;em&gt;only 39KiB&lt;/em&gt;. I’m using the KiB unit of measurement which equates to 1024 bytes. I still find it hard to believe as the game contains so much! In this blog post I’ll go into some of the nerdy details.&lt;/p&gt;

&lt;h2 id=&quot;playdate&quot;&gt;Playdate?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; is a handheld gaming system with a unique crank input method. I don’t use the crank in this game, but I have done in the past and will do again in the future.&lt;/p&gt;

&lt;p&gt;If you own a Playdate you can buy the game now at &lt;a href=&quot;https://play.date/games/yoyozo/&quot;&gt;play.date/games/yoyozo/&lt;/a&gt;. If you don’t own a Playdate, well, &lt;a href=&quot;https://play.date&quot;&gt;what are you waiting for&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-teaser.gif#playdate&quot; alt=&quot;YOYOZO&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;butwhy&quot;&gt;But…&lt;em&gt;why?&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;The drive to produce a small game started after I sent the first playable version to testers. Steve at &lt;a href=&quot;http://scenicroutesoftware.com&quot;&gt;&lt;em&gt;Scenic Route Software&lt;/em&gt;&lt;/a&gt;, purveyor of quality video games, commented how tiny the game was. At that point it was 18KiB, but had no music or sound effects or polish. There was a long way to go.&lt;/p&gt;

&lt;p&gt;Even so, I wondered how doable it would be to build the game out with an eye on keeping file size “low”. I thought back to the days of my youth where whole games would fit on a single floppy disk, with room to spare. If they could do it, shouldn’t I give it a try?&lt;/p&gt;

&lt;p&gt;It’s worth noting that even with this mindset, I didn’t make a huge sustained effort to meet the goal. On the contrary, it was just something I simply kept in mind as development proceeded. For that reason, I’m sure there are more ways the game could be made even smaller than it is, with the exact same code and content. For example, I never tried finding the most optimal format for things like music and particle data which are the two largest sets of embedded data.&lt;/p&gt;

&lt;p&gt;Finally, this is not a challenge, or me throwing down the gauntlet in any way. It’s easy enough to make a smaller game, be it similar or entirely different, you’d just have to make different choices along the way. This was just me doing something nerdy as an additional constraint on top of the already enjoyable constraints of developing for Playdate.&lt;/p&gt;

&lt;p&gt;That said, I think every game developer should regularly make a point of writing code for an underpowered device as part of their own personal development—there are so many lessons to learn.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;reasons&quot;&gt;Reasons&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The main reason for the small file size is the fact that &lt;em&gt;the game does not use any digital sound files, and very few bitmap images&lt;/em&gt; (the launch card and animation have to be bitmaps, and in-game only the logo and fonts are bitmaps). Game graphics are all drawn using only shapes (lines, rects, circles) and fills (black, white, and dither patterns).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A second reason is that whilst I use the base Playdate Lua SDK, &lt;em&gt;I don’t use any of the additional “CoreLibs”&lt;/em&gt;. The only extra graphics functions I needed were for drawing outlined or filled circles, so I use two of my own wrapper functions that are similar to those from CoreLibs/graphics but mine are smaller and more specific. For timers, I use a simple frame/tick system, an approach which has pros and cons, but it’s good enough for me.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A third reason is that I made the tough decision to reduce system assets, which means &lt;em&gt;there is no animated launcher card&lt;/em&gt;. This was a tough one, but it added so much to the file size I decided against it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, I noticed that &lt;em&gt;including data inside your game code&lt;/em&gt; often trumps how well you can compress it and store it externally. For example I tried compressing the music data and storing it in an external file, but the game final file size was larger than if I embedded the data in my Lua code. Plus, it’s faster as it doesn’t need to load an additional external file.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;breakdown&quot;&gt;Breakdown&lt;/h2&gt;

&lt;p&gt;I thought it would be cool to outline the main features and how each contributes to the total file size. Note that the sizes are expressed as quantities of the compiled binary, rather than uncompiled source code. It’s also worth noting that a blank project with an empty update function results in a compiled binary of only 147 bytes. Playdate compiles to Lua bytecode.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-chart.png&quot; alt=&quot;CHART&quot; /&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Content&lt;/th&gt;
      &lt;th&gt;Kilobytes&lt;/th&gt;
      &lt;th&gt;%&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Main code&lt;/td&gt;
      &lt;td&gt;19&lt;/td&gt;
      &lt;td&gt;49&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Two music tracks&lt;/td&gt;
      &lt;td&gt;5.5&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Three bitmap fonts&lt;/td&gt;
      &lt;td&gt;2.5&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Synthesized sound effects&lt;/td&gt;
      &lt;td&gt;2.5&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Custom particle system&lt;/td&gt;
      &lt;td&gt;2.0&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Animated system icon&lt;/td&gt;
      &lt;td&gt;2.0&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Animated system card&lt;/td&gt;
      &lt;td&gt;2.0&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Pulp music engine (modified)&lt;/td&gt;
      &lt;td&gt;1.5&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Online scoring system&lt;/td&gt;
      &lt;td&gt;0.5&lt;/td&gt;
      &lt;td&gt;1.25&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;How to play instructions&lt;/td&gt;
      &lt;td&gt;0.4&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Custom soundtrack capability&lt;/td&gt;
      &lt;td&gt;0.1&lt;/td&gt;
      &lt;td&gt;0.25&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;“Main code” contains: physics simulation, game structure and state management, multi-layered scoring and bonus system, score/stat tracking, loading and saving stats and settings, path recording and playback, animated introduction, plus the following &lt;em&gt;dynamic&lt;/em&gt; systems: scrolling starfield, screen shake, music system, sound effects system. All running at 40fps.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;abandoned-and-removed-features&quot;&gt;Abandoned and removed features&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I tried a bunch of stuff during development. Such as asteroid fields or meteor showers that introduced obstacles that needed to be avoided, and black holes that would magnetically attract the ball. But I felt they detracted from the pureness of the concept, so I didn’t go any further with them.&lt;/li&gt;
  &lt;li&gt;The positions of stars are randomly generated, but I have implemented a fixed “daily” layout in the game, which is really fun. It’s a different experience to be able to play the same layout over and over, improving your execution of the same moves and eking out higher and higher scores. I did plan to reintroduce that option when Playdate Catalog got score boards that reset daily, but by the time that happened &lt;a href=&quot;/2025/04/15/when-playdate-stopped-being-fun/&quot;&gt;I was no longer developing Playdate&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;manualguide&quot;&gt;Manual/Guide&lt;/h2&gt;

&lt;p&gt;I really loved the manuals that came with games in the 8-bit and 16-bit era. So I thought it would be fun to write a manual/player’s guide in the old-school style. I love reading those sorts of manuals, where the developer gives you a little glimpse behind the curtain so you get an understanding of how the game works, with some small hints and tips littered throughout—for the most inquisitive players! If that sounds like your thing, &lt;a href=&quot;https://play.date/games/yoyozo/#gameListingMoreInfo&quot;&gt;download the manual from the game page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://play.date/games/yoyozo/#gameListingMoreInfo&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yoyozo-manual.png&quot; alt=&quot;YOYOZO Manual&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;p&gt;I worked on YOYOZO from September 5th to 27th, submitting it to Catalog on 21st and polishing it for the final week after that. After the game was approved I added online score boards one evening just prior to launch. It was in review and waiting for release longer than it was in development!&lt;/p&gt;

&lt;p&gt;The purpose of this section is not to say that developing a game quickly is better than developing one slowly, or vice versa, but rather to show the importance of scoping a game well and then sticking to the plan.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2023-09-05—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1699108587732119834&quot;&gt;initial prototype&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-09-07—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1699784106505290093&quot;&gt;playable prototype&lt;/a&gt; (3 days)&lt;/li&gt;
  &lt;li&gt;2023-09-07—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1699890693366517890&quot;&gt;quick progress&lt;/a&gt; (3 days)&lt;/li&gt;
  &lt;li&gt;2023-09-09—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1700612152707461396&quot;&gt;came up with the name&lt;/a&gt; (5 days)&lt;/li&gt;
  &lt;li&gt;2023-09-14—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1702103698749505670&quot;&gt;polishing and balancing&lt;/a&gt; (10 days)&lt;/li&gt;
  &lt;li&gt;2023-09-20—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1704608465522487681&quot;&gt;revelatory physics tweak&lt;/a&gt; (16 days)&lt;/li&gt;
  &lt;li&gt;2023-09-21—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1704991183573831711&quot;&gt;addicted to my own game&lt;/a&gt; (17 days)&lt;/li&gt;
  &lt;li&gt;2023-09-21—submitted to Catalog (17 days)&lt;/li&gt;
  &lt;li&gt;2023-09-23—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1705676134245875750&quot;&gt;game over replay&lt;/a&gt; (19 days)&lt;/li&gt;
  &lt;li&gt;2023-09-26—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1706765228879253972&quot;&gt;layout design using spreadsheet&lt;/a&gt; (22 days)&lt;/li&gt;
  &lt;li&gt;2023-09-26—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1706772586510643560&quot;&gt;game over stats screen&lt;/a&gt; (22 days)&lt;/li&gt;
  &lt;li&gt;2023-09-27—final version (23 days)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…and then some waiting until:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2023-10-10—approved for Catalog (36 days)&lt;/li&gt;
  &lt;li&gt;2023-11-19—added online scoreboards (76 days)&lt;/li&gt;
  &lt;li&gt;2023-11-21—&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1727030817116053611&quot;&gt;released on Catalog&lt;/a&gt; (78 days)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…so that is 78 days (11 weeks) from initial prototype to being live on the Catalog store!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;credits&quot;&gt;Credits&lt;/h2&gt;

&lt;p&gt;YOYOZO is a game by Matt Sephton, with music by Jamie Hamshere.&lt;/p&gt;

&lt;p&gt;Thanks to CANO-Lab and Testers.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/11/26/easter-egg-emoji-converting-pixels-into-particles/&quot;&gt;Easter egg emoji: converting pixels into particles&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/12/09/dynamic-music-and-sound-techniques-for-video-games/&quot;&gt;Dynamic music and sound techniques for video games&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.date/games/yoyozo/#gameListingMoreInfo&quot;&gt;&lt;em&gt;YOYOZO&lt;/em&gt; manual/player’s guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;elsewhere&quot;&gt;Elsewhere&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;2024-10-16—&lt;a href=&quot;https://gamerepublic.net/news/best-indie-game-made-in-the-north-of-england-2024-award/&quot;&gt;Game Republic 2024 Awards: Best Indie Game Made in the North of England&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2024-03-08—&lt;a href=&quot;https://play.date/games/community-awards-2023/&quot;&gt;Playdate Community Awards 2023: Best Arcade Game&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-12-27—&lt;a href=&quot;https://arstechnica.com/gaming/2023/12/ars-technicas-best-video-games-of-2023/7&quot;&gt;Ars Technica: YOYOZO wins GOTY accolade!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-30—&lt;a href=&quot;https://arstechnica.com/gaming/2023/11/my-long-quest-to-revive-a-90s-windows-gaming-cult-classic/&quot;&gt;Ars Technica&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-24—&lt;a href=&quot;http://eepurl.com/iEHB8M&quot;&gt;Hacker Newsletter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-23—&lt;a href=&quot;https://www.timeextension.com/news/2023/11/yoyozo-is-a-new-playdate-game-inspired-by-the-japanese-cult-classic-pendulumania&quot;&gt;Time Extension&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-22—&lt;a href=&quot;https://news.ycombinator.com/item?id=38372936&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2023-11-22—&lt;a href=&quot;https://tildes.net/~games/1cbz/yoyozo_or_how_i_made_a_playdate_game_in_39kb&quot;&gt;Tildes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 21 Nov 2023 23:59:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/11/21/yoyozo-how-i-made-a-playdate-game-in-39kb/</guid>
        </item>
      
    
      
        <item>
          <title>OpenSCAD to Sprite Sheet workflow</title>
          <description>&lt;p&gt;I just released the “OpenSCAD to Spritesheet” workflow I created for &lt;a href=&quot;/tag/dailydriver/&quot;&gt;Daily Driver&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/gingerbeardman/openscad-spritesheet&quot;&gt;github.com/gingerbeardman/openscad-spritesheet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a Frankenstein mish-mash of a Makefile and several shell scripts that evolved over many months/years. Initial rendering is done using OpenSCAD, and post-processing is done using ImageMagick. Model poses and rendering variations are controlled by variables in either the shell script or passed through to the model. The whole process is optimised to do as much in parallel as I could figure. More info at the link above! 🚗💨&lt;/p&gt;

&lt;h2 id=&quot;post-processing&quot;&gt;Post Processing&lt;/h2&gt;

&lt;p&gt;After exporting all frames there is some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image magick&lt;/code&gt; work to process the files as follows:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;stitch frames together into a single sprite sheet&lt;/li&gt;
  &lt;li&gt;split sprite sheet into RGBA channels&lt;/li&gt;
  &lt;li&gt;process channels to recolour and dither as required&lt;/li&gt;
  &lt;li&gt;recombine processed channels into new sprite sheet image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can read about that in a &lt;a href=&quot;/2021/06/05/channelling-rgb-into-1bit/&quot;&gt;previous blog post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;A full build of 36 cars is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;3GHz 6-core Intel Mac mini 32GB
    &lt;ul&gt;
      &lt;li&gt;100% CPU for ~26 minutes&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;M1 Pro 10-core MacBook Pro 16GB
    &lt;ul&gt;
      &lt;li&gt;70% CPU for ~9 mins&lt;/li&gt;
      &lt;li&gt;about 3x speedup&lt;/li&gt;
      &lt;li&gt;approx 16 seconds per car&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s parallel 3D rendering, PNG writing &amp;amp; compositing &amp;amp; processing, and copying of ~140K files (which takes up ~0.5GB of disk space).&lt;/p&gt;

&lt;h2 id=&quot;example-model&quot;&gt;Example Model&lt;/h2&gt;

&lt;p&gt;Not to scale! Sizes of features are exagerated to allow for them to appear correct when rendered at a very small size.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/openscad-spritesheet-model-car.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;example-output&quot;&gt;Example Output&lt;/h2&gt;

&lt;p&gt;990 frames each for car and shadow, total of 1980 frames per sprite sheet. Each sprite sheet takes up about ~400KB of RAM on Playdate, and only one is loaded at a time.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/posts/openscad-spritesheet-car-table-38-38.png&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/openscad-spritesheet-car-table-38-38.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 04 Oct 2023 15:19:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/10/04/openscad-to-sprite-sheet/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/10/04/openscad-to-sprite-sheet/</guid>
        </item>
      
    
      
        <item>
          <title>The first colour Playdate game?</title>
          <description>&lt;blockquote&gt;
  &lt;p&gt;This blog post assumes some familiarity with &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt; (a handheld game console with a cool crank control scheme), &lt;a href=&quot;https://play.date/dev/&quot;&gt;Playdate SDK&lt;/a&gt; and the &lt;a href=&quot;https://www.lua.org/manual/5.4/&quot;&gt;Lua programming language&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;During the development of my forthcoming Playdate game &lt;em&gt;&lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Ball und Panzer Golf&lt;/a&gt;&lt;/em&gt; (tentative title), I wanted to be able to draw to the debug layer from anywhere in my code. The SDK allows you to draw to the debug layer only from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drawDebug&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;After filing a &lt;a href=&quot;https://devforum.play.date/t/additional-way-to-do-debug-draw-from-anywhere-in-code/11735&quot;&gt;feature request&lt;/a&gt; I thought about it some more and &lt;a href=&quot;&quot;&gt;came up with a workaround&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. (on initialisation) create a full screen opaque image&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;disp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;overlay&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;disp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;disp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kColorBlack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. (anywhere in your code) draw into that using pushContext (or lockFocus)&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pushContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kColorWhite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setLineWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drawCircleAtPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- draw some debug stuff into our overlay image&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. (in debugDraw function) draw the single image of our collected debug drawing&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;playdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debugDraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- draw our overlay image containing all debug draws&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gfx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kColorBlack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- blank overlay ready for the next update&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means I can draw debug info about a thing from the same code and logic responsible for that thing. For me, with this game, that makes a lot of sense.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/playdate-debugdraw.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;abusing-the-system&quot;&gt;Abusing the system&lt;/h2&gt;

&lt;p&gt;After debugging the positions of everything during my collision logic, it occurred to me that I could abuse this system to give the game a colour overlay.&lt;/p&gt;

&lt;p&gt;I do this by using the debug draw in the opposite way to how it’s supposed to be used. Instead of drawing just the debug information, I set the hole screen to draw in colour and then—in the same way as above—at various points in my code &lt;em&gt;I punch out areas of the screen I do not want drawn in colour&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I’m not quite drawing everything twice, as the areas that are punched out are simple shapes approximating the elements in my game. Plus, this is made easier for me because everything in the game is already being drawn only with filled shapes.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 5/3;&quot; videoid=&quot;fqv1kwfW5r8&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;One interesting thing about this technique is that changing the contrast (dither pattern opacity) of the golf greens only when running in “colour mode” on the Simulator made things look better. That’s to say that adding colour also adds an extra complexity with regards to contrast. I think that’s the only change to the graphics I’ve done so far but there is opportunity for more.&lt;/p&gt;

&lt;p&gt;When I sent a build out to testers I put a cryptic note in the changelog “added: chartreuse tinted glasses mode” but only one tester figured out what it was referring to. I had asked ChatGPT to suggest a colour that sounds like a shade of red, but is actually a shade of green: it suggested chartreuse (and so I use the “proper” chartreuse hex colour for the base colour of my green layer).&lt;/p&gt;

&lt;h2 id=&quot;multi-colour&quot;&gt;Multi-colour?&lt;/h2&gt;

&lt;p&gt;This approach could be taken further if the Playdate SDK allowed multiple colours to be used for debug drawing, &lt;a href=&quot;https://devforum.play.date/t/support-mutiple-colors-in-debugdraw/5848&quot;&gt;keep an eye on this feature request&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;physical-overlays&quot;&gt;Physical overlays&lt;/h2&gt;

&lt;p&gt;Back in October 2021 I bought transparency film in a range of colours to make a physical screen overlay, inspired by early arcade games like Space Invaders and the Vectrex gaming system, which worked but is obviously more hassle as the transparency picks up lint and gets dirty really quickly. This split of blue/green was for sky/grass in a 3D golf game.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/playdate-physical-overlays.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/&quot;&gt;Ball und Panzer Golf: making a Playdate game in a week&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 09 Jul 2023 12:59:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/07/09/the-first-colour-playdate-game/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/07/09/the-first-colour-playdate-game/</guid>
        </item>
      
    
      
        <item>
          <title>Ball und Panzer Golf: making a Playdate game in a week</title>
          <description>&lt;p&gt;I’ve been following the X68000 Z mini computer since it’s announcement in the hope that it will bring new activity to the X68000 scene and it seems to be having that effect. In one video from the recent 「68の日」(“68 Day”, named after the date written in Japanese order, 6-8, that’s 8th June the most special day of the year for X68000 fans) &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1669909753592512512?s=61&amp;amp;t=vJGphXuN310nHUu1fN6c7Q&quot;&gt;I spotted&lt;/a&gt; a interesting looking single screen golf game:&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;Nwte3wm6lzo&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;h2 id=&quot;hello-kata68k&quot;&gt;Hello kata68k&lt;/h2&gt;

&lt;p&gt;It was Ball und Panzer Golf an indie/doujin game by &lt;a href=&quot;https://twitter.com/kata68k&quot;&gt;@kata68k&lt;/a&gt; for the Sharp X68000 series of Japanese personal computers and the recent &lt;a href=&quot;https://www.zuiki.co.jp/products/x68000z/&quot;&gt;&lt;em&gt;Zuiki X68000 Z&lt;/em&gt;&lt;/a&gt; mini system, a new emulator based reimagining of the original classic computer. The name is a pun on the anime series &lt;a href=&quot;https://en.wikipedia.org/wiki/Girls_und_Panzer&quot;&gt;&lt;em&gt;Girls und Panzer&lt;/em&gt;&lt;/a&gt; and its shortened version is &lt;em&gt;BuPG&lt;/em&gt; which I assume is a pun on &lt;em&gt;PUBG&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;kata68k’s game, as the name implies, is golf but with a tank. It was &lt;a href=&quot;https://twitter.com/kata68k/status/1634209609069076480&quot;&gt;created in May 2023 and fine tuned for a few weeks&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/kata68k/status/1666099628947968006&quot;&gt;released in time for “68 Day”&lt;/a&gt;. It’s a single player game where you use the tank to shoot holes-in-one on a golf course and try to destroy all flags. All this to say it plays like golf, kinda, but with a focus on high scores.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Aside: my favourite source of X68000 content is the &lt;a href=&quot;https://www.youtube.com/user/pipipicpsf&quot;&gt;&lt;em&gt;PipitanTV&lt;/em&gt; YouTube channel&lt;/a&gt;, run by &lt;a href=&quot;https://twitter.com/pipixvi&quot;&gt;@pipixvi&lt;/a&gt;, which has a &lt;a href=&quot;https://www.youtube.com/watch?v=FMrsHfuuTR8&amp;amp;t=22s&quot;&gt;longer, screen capture video&lt;/a&gt; of Ball und Panzer Golf.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I played Ball und Panzer Golf v0.94 using an X68000 emulator and was instantly hooked, by the strange mashup concept and also by the scoring mechanisms that were involved. Kata’s game design values and methods align with my own to a surprising degree. kata68k grew up with the X68000 much like I grew up with another Motorola 68000-based computer: the Atari ST. We’re roughly the same age and have similar interests in many ways.&lt;/p&gt;

&lt;p&gt;Anyway, I had great fun figuring out the different types of shots and opportunities to increase my scoring ability during my few plays of the game. Once I’d figured them out, it became a task of improving my skill controlling the tank and the shot power. The shot mechanism itself is worthy of a mention: there is no real charging of the shot and the ball starts to move immediately. What you do control is the moment the ball starts to come back down to Earth. It’s a very strange way of controlling the ball, but oddly satisfying. It’s reminiscent of the two tap system that sets power in most golf games, but at the same time feels completely alien.&lt;/p&gt;

&lt;h2 id=&quot;enter-playdate&quot;&gt;Enter Playdate&lt;/h2&gt;

&lt;p&gt;I currently spend my time creating games for &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt;, a handheld gaming system with a black and white screen and a unique crank control that can be used as a method of input. Whilst on a walk in the park I couldn’t stop thinking of kata68k’s game and how it might work on Playdate. When I got back to my computer I wrote a little bit of Lua code to draw an elliptical golf green on screen, then added a hole, a flag pole, and a flag with a number on it. Then I added a loop to generate random positions and drew 18 holes, adjusting the size so they all fitted a bit better. It might just work.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-01.png#playdate&quot; alt=&quot;PNG&quot; title=&quot;The first 18 holes, eat your heart out &amp;lt;em&amp;gt;Pebble Beach no Hatou&amp;lt;/em&amp;gt;!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After a quick dinner, it was time to draw the tank. I really didn’t want to slow down my pace of progress so I decided to keep drawing the graphical elements in code using filled shapes rather then have to draw a tank in pixels. Another option would have been to use one of the cars from my game &lt;a href=&quot;/2021/08/23/daily-driver-teaser-artwork/&quot;&gt;Daily Driver&lt;/a&gt;, but the path of least resistance was to draw a filled ellipse along with a line to show the turret position.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-02.png#playdate&quot; alt=&quot;PNG&quot; title=&quot;Rudimentary tank and turret drawn using an filled ellipse and a thick line&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;day-1&quot;&gt;Day 1&lt;/h2&gt;

&lt;p&gt;That first day everything fell into place perfectly, with little friction and no refactoring. I started from a blank file and wrote just under 400 lines of code. The two most complicated elements were the randomised background and limiting the tank to its circular area, but I’d done similar things before so there was no problem solving involved, just pure implementation. In fact, a lot of this quick prototype made use of tricks and techniques I’d figured out over the past few years of Playdate development, in particular during the development of my game &lt;a href=&quot;/tag/dailydriver/&quot;&gt;Daily Driver&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the end of the first day you could drive the tank around the screen, fire the ball at an angle selected using the crank or d-pad, and when you run out of balls it would trigger game over. What it didn’t have is any logic that would collide the ball with the holes, point scoring, or any sort of win state. For some reason at this point I thought it would be cool to have a black tank with three wheels.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-03.gif#playdate&quot; alt=&quot;GIF&quot; title=&quot;The state of the game the end of the first day&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;day-1-timeline&quot;&gt;Day 1: Timeline&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Time&lt;/th&gt;
      &lt;th&gt;Event&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;15:40&lt;/td&gt;
      &lt;td&gt;draw a single “hole”: flag, hole, green&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;16:00&lt;/td&gt;
      &lt;td&gt;loop to draw 18 holes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;17:00&lt;/td&gt;
      &lt;td&gt;(dinner)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;18:00&lt;/td&gt;
      &lt;td&gt;draw tank&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;18:20&lt;/td&gt;
      &lt;td&gt;(ask permission from kata68k)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;19:00&lt;/td&gt;
      &lt;td&gt;background (interesting use of Perlin and random)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;20:00&lt;/td&gt;
      &lt;td&gt;add controls to tank&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;20:10&lt;/td&gt;
      &lt;td&gt;(send update to kata68k)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;21:00&lt;/td&gt;
      &lt;td&gt;limit tank to circular area (tricky but fun)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;22:00&lt;/td&gt;
      &lt;td&gt;ball moving&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;22:10&lt;/td&gt;
      &lt;td&gt;(kata68k confirms he’s OK with my version)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;22:30&lt;/td&gt;
      &lt;td&gt;add game states&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;23:00&lt;/td&gt;
      &lt;td&gt;add ball height capability&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;23:45&lt;/td&gt;
      &lt;td&gt;(send update to kata68k)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;00:26&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://twitter.com/gingerbeardman/status/1670573820581650434&quot;&gt;tweet about it&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;week-1&quot;&gt;Week 1&lt;/h2&gt;

&lt;p&gt;The following day I added a first draft of collisions and scoring. There was slower progress, but it was still very steady with no problems encountered. I was keenly aware that the collision and scoring were very naïve and that I would have to refine and improve them going forward. But, regardless, at the end of the second day it was possible to play a complete round of tank golf!&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-04.gif#playdate&quot; alt=&quot;GIF&quot; title=&quot;How the game was shaping up at the end of the second day&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The next two days consisted of fine tuning, polishing, play testing, bug fixing, adding sound effects, and so on. I even managed to record a GIF where I got all 18 flags …my first speed run!? I also received some great early encouragement and feedback from Playdate Squad community members: Donald &lt;a href=&quot;https://twitter.com/Guv_Bubbs&quot;&gt;@Guv_Bubbs&lt;/a&gt;, Steve &lt;a href=&quot;https://twitter.com/ScenicSoftware&quot;&gt;@ScenicSoftware&lt;/a&gt;, Atsu &lt;a href=&quot;https://twitter.com/SquidGodDev&quot;&gt;@SquidGodDev&lt;/a&gt;, Neven &lt;a href=&quot;https://twitter.com/mrgan&quot;&gt;@neven&lt;/a&gt; and of course &lt;a href=&quot;https://twitter.com/kata68k&quot;&gt;@kata68k&lt;/a&gt; himself! The game was shaping up nicely and coming together very quickly.&lt;/p&gt;

&lt;p&gt;Opportune timing meant that I could get the game in the hands of some testers on a live stream, over at IGDA Twin Cities (MN, USA) as part of their monthly Playtest. Thanks to &lt;a href=&quot;https://twitter.com/Mark_LaCroix&quot;&gt;Mark LaCroix&lt;/a&gt; for sorting that out! It was great to watch them play the game for the first time as they discovered the details of gameplay, mechanics, controls, and scoring! I even spotted a bug.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;qZq3-N1MczA&quot; params=&quot;start=3837&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;For the rest of the week I polished and played, addressing areas that I thought could be improved. I added accessibility improvements, more opportunities to score, better hole randomisation, even wind effects, and so much more besides.&lt;/p&gt;

&lt;p&gt;For the last couple of days of the week I kept release notes, as I felt the pace of progress slowing down towards the end of my self-imposed deadline of one week. I would categorise most changes in those final days as either quality of life improvements or minor bug fixes.&lt;/p&gt;

&lt;p&gt;I had not optimised any of the code and was targeting the default 30 frames per second. On the final evening I optimised all text drawing in my main update path, as I could see that was responsible for a huge portion of where my game was spending its time, with the CPU pegged at 100% and the frame rate not able to hit the target 30fps. So the flags with numbers on were pre-rendered as images during initialisation, and the HUD is drawn only when its contents change, and the image is cached for use at other times. These two small and quick optimisations reduced the CPU usage by 20% and put me at a solid 30fps.&lt;/p&gt;

&lt;p&gt;There are many more optimisations to be made but this is not the time to do them. There’s too much still to do and I don’t want to lose focus. But for example: I’m not currently using the Playdate SDK Sprite system and am instead doing things the traditional way of drawing everything every update, so I’m positive I can get some good gains by drawing to a few different sprite layers. There are also some functions I call regularly, such as one that counts remaining holes, that can be optimised or avoided by improving my game logic. I’m confident I can get the CPU time down a good bit more. There’s no real need to do so, but I figure anything that will help reduce power usage or is good for the player is a honourable responsibility for a developer with a conscience to take on. If that goes well I may even increase the frame rate for smoother ball movement.&lt;/p&gt;

&lt;h2 id=&quot;shaping-up&quot;&gt;Shaping up&lt;/h2&gt;

&lt;p&gt;All the graphics are still composed with filled ellipses, rectangles and lines, varying their dithering patterns to provide different textures. I really leaned into this and over the course of the week fine tuned the tank from a three-wheeled blob to a high contrast, detailed, carefully animated sprite that you might think has been rendered externally. Maybe in a forthcoming post I can put together an exploded diagram of how it’s drawn?&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-05.gif#playdate&quot; alt=&quot;GIF&quot; title=&quot;Ball und Panzer Golf for Playdate, at the end of the first week&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;The only things I didn’t manage to fit in in my week sprint were a couple of animations I think will help make the game feel even higher quality and that will increase players ability to read/understand what is happening on screen. I need to make some more changes to the wind feature and the way the flag flaps in the wind. Currently the flag direction is correct but I’d like the length and frequency to be relative to the strength of the wind.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Pretty much all of the maths in this game is high school algebra and trigonometry, wrapped up in some smoke and mirrors to make it feel magical.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also on the task list are a couple more sound effects, with the goal being one sound effect for each important event or action in the game. I feel that sounds cues are as important as visual cues and players could pick up on one or the other so there should ideally be parity.&lt;/p&gt;

&lt;p&gt;I can’t keep up the insanely fast pace of development from this first week, not only because of the physical and mental toll it would take but also because the quick wins of the prototype phase are now gone. To add the animations I previously mentioned, the first serious refactoring of part of the code will be needed. So there is no choice but for progress to be slower from this point at least for a while.&lt;/p&gt;

&lt;p&gt;The big remaining task that will take a lot longer than a week is game structure and progression. I have ideas of how I can package the structure of the game now into a short experience with increasing difficulty level and unlimited replay-ability.&lt;/p&gt;

&lt;p&gt;But the bigger question is do I want it to be bigger than that? There are no shortage of ideas how how to mashup to concept of tanks and golf, only a shortage of time and budget to make it happen. I could even add a mini-golf type of experience where you’re playing a round of single screen holes with additional hazards pulled from both the golf and tank world.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;launched&quot;&gt;Launched!&lt;/h2&gt;

&lt;p&gt;My version of Ball und Panzer Golf was renamed Fore! Track and is available for Playdate via Catalog &lt;a href=&quot;https://play.date/games/fore-track/&quot;&gt;play.date/games/fore-track/&lt;/a&gt; or on &lt;a href=&quot;https://gingerbeardman.itch.io/fore-track&quot;&gt;itch where there’s a bargain offline version&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/ball-und-panzer-golf-fore-track.gif#playdate&quot; alt=&quot;GIF&quot; title=&quot;Demonstration of the launch version of &amp;lt;em&amp;gt;Fore! Track&amp;lt;/em&amp;gt;&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2023/07/09/the-first-colour-playdate-game/&quot;&gt;The first colour Playdate game?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 26 Jun 2023 22:11:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/06/26/ball-und-panzer-golf-making-a-playdate-game-in-a-week/</guid>
        </item>
      
    
      
        <item>
          <title>Sparrow Solitaire Tile Workshop</title>
          <description>&lt;p&gt;A little known feature of &lt;a href=&quot;https://sparrowsolitaire.com&quot;&gt;Sparrow Solitaire&lt;/a&gt; is its ability to load user-generated content from files copied onto the &lt;a href=&quot;https://play.date&quot;&gt;Playdate&lt;/a&gt;. One day I thought it would be cool to combine two tile sets, so I built a web app to do it!&lt;/p&gt;

&lt;p&gt;A wild tile set builder appears! &lt;a href=&quot;https://sparrowsolitaire.com/workshop/&quot;&gt;sparrowsolitaire.com/workshop/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-in-1&quot;&gt;3-in-1&lt;/h2&gt;

&lt;p&gt;As well as allowing you to cherry pick tiles from existing sets (and sharing that selection data with people), you can also load your own image data into the “user” row. This is done using the Pasteboard text area, which accepts a few different types of data.&lt;/p&gt;

&lt;p&gt;First it accepts a PNG URL which will be loaded into the user row and must be the correct dimensions.&lt;/p&gt;

&lt;p&gt;Secondly it accepts data:image (recommended &amp;amp; most versatile) which can be of any dimension. You can easily copy data:image straight out of the &lt;a href=&quot;https://www.piskelapp.com&quot;&gt;Piskel&lt;/a&gt; pixel art web app. You can also generate it on the command line, using the small script below, or using &lt;a href=&quot;https://www.alfredforum.com/topic/20306-clipboard-image-to-data-uri/&quot;&gt;an Alfred workflow&lt;/a&gt; or similar automation.&lt;/p&gt;

&lt;noscript&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/c19ac6d2b8565fea9e3e45909ddddc9b&quot;&gt;View the source code as a Gist&lt;/a&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/gingerbeardman/c19ac6d2b8565fea9e3e45909ddddc9b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Thirdly, and finally, if you’d rather create a full tile set of your own, you can do it all in &lt;a href=&quot;https://www.piskelapp.com&quot;&gt;Piskel&lt;/a&gt; and save it online as a GIF. Paste this URL into Tile Workshop and you can save it straight to an image format suitable for use on your Playdate.&lt;/p&gt;

&lt;p&gt;Please do get in touch if you create any tile sets of your own!&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-solitaire-tile-workshop.png&quot; alt=&quot;PNG&quot; title=&quot;Sparrow Solitaire Tile Workshop&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 01 May 2023 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/05/01/sparrow-solitaire-tile-workshop/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/05/01/sparrow-solitaire-tile-workshop/</guid>
        </item>
      
    
      
        <item>
          <title>Sparrow Solitaire for Playdate</title>
          <description>&lt;p&gt;I’ve &lt;a href=&quot;/2022/07/13/sparrow-solitaire-for-playdate/&quot;&gt;previously&lt;/a&gt; written about the Playdate game Sparrow Solitaire, when we released the Early Access version of the game. That was almost 9 months ago and a lot has changed!&lt;/p&gt;

&lt;p&gt;This week the &lt;a href=&quot;https://vogelscript.itch.io/sparrow-solitaire/devlog/515286/sparrow-solitaire-v10&quot;&gt;hugely expanded full version&lt;/a&gt; of the game &lt;a href=&quot;https://vogelscript.itch.io/sparrow-solitaire&quot;&gt;released on itch.io&lt;/a&gt;, where it’s been for sale for a while, &lt;a href=&quot;https://play.date/games/sparrow-solitaire/&quot;&gt;and on Playdate Catalog&lt;/a&gt; the new on-device store. It even got its &lt;a href=&quot;https://sparrowsolitaire.com&quot;&gt;own website&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This post is a continuation of the history of the development of the game, going into the conceptual decisions and visual inspiration.&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;Wb5fw7rCfl4&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;mahjong-or-not-mahjong-that-is-the-question&quot;&gt;&lt;em&gt;Mahjong&lt;/em&gt; or &lt;em&gt;not Mahjong&lt;/em&gt;, that is the question?&lt;/h2&gt;

&lt;p&gt;This type of game is commonly called Mahjong Solitaire, because it uses mahjong tiles to form the layouts and it’s usually a single-player game. But the traditional tiles are somewhat inscrutable to newcomers. They are from a totally different game that goes by the name of &lt;em&gt;Mahjong&lt;/em&gt;, which further confuses the situation. For this reason most Mahjong Solitaire games use alternative, more recognisable and approachable tile patterns.&lt;/p&gt;

&lt;p&gt;Whilst reading about the history of mahjong, I discovered that in Chinese the game was originally called 麻雀 (pinyin: máquè)—meaning &lt;em&gt;sparrow&lt;/em&gt;. This seemed like a nice alternative name for the game, allowing me to use alliteration, and avoiding the complexity that comes with the traditional mahjong tiles, and of course having cultural sensitivity top of mind.&lt;/p&gt;

&lt;h2 id=&quot;a-brief-history-of-mahjong-solitaire&quot;&gt;A brief history of Mahjong Solitaire&lt;/h2&gt;

&lt;p&gt;Mahjong Solitaire is widely considered a Western invention in much the same way as French-suited playing cards and their related Patience/Solitaire games, but both have their origins in China.&lt;/p&gt;

&lt;p&gt;Computer game Mahjong Solitaire was originally &lt;a href=&quot;https://forest-flower.com/university_old/note.php?timestamp=2019-09-09+03%3A41%3A00&quot;&gt;created by Brodie Lockard in 1981 on the PLATO system and named Mah-Jongg&lt;/a&gt; after the game that uses the same tiles for play. Lockard &lt;a href=&quot;https://www.salon.com/2017/11/19/how-a-little-known-computer-network-system-changed-the-history-of-the-internet/&quot;&gt;claimed that it was based on a centuries-old Chinese game called “the Turtle”&lt;/a&gt; that he had been shown whilst in hospital after a serious accident that left him paralysed from the neck down.&lt;/p&gt;

&lt;p&gt;Not only did Brodie create the PLATO version in 1981 using only his mouth to type the code and draw the graphics, but he went on to make the Apple Macintosh version which was published in 1986 by Activision, as Shanghai, which sold millions of copies. Shanghai II came in 1989 and a whole new genre of games was born.&lt;/p&gt;

&lt;h2 id=&quot;wherefore-art-thou-macintosh&quot;&gt;Wherefore art thou Macintosh?&lt;/h2&gt;

&lt;p&gt;An interesting point about the first two versions of the computer game: they both had monochrome displays (also referred to as 1-bit). &lt;a href=&quot;https://forest-flower.com/university_old/note.php?timestamp=2019-09-09+03%3A41%3A00&quot;&gt;PLATO was orange on black&lt;/a&gt;, and &lt;a href=&quot;https://macgui.com/downloads/?file_id=14895&quot;&gt;Macintosh was black on white&lt;/a&gt;. Funnily enough Playdate is also monochrome: dark grey on pale grey. Upon seeing the Sharp Memory LCD display that is used in the Playdate I was instantly reminded of the original Apple Macintosh. I mean, I still use &lt;a href=&quot;/2021/04/17/turning-an-ipad-pro-into-the-ultimate-classic-macintosh/&quot;&gt;System 7 on an iPad Pro&lt;/a&gt; and have a 1991 Macintosh Classic at home so it did not take much to remind me, but it did.&lt;/p&gt;

&lt;p&gt;My initial explorations around 1-bit graphics happened on Macintosh, long before I had ever held a Playdate in my hands. I explored fill patterns, dithering algorithms (eventually discovering and popularising a &lt;a href=&quot;https://hbfs.wordpress.com/2013/12/31/dithering/&quot;&gt;little known algorithm&lt;/a&gt;), old drawing software optimised for 1-bit graphics, and diving head first into old clip art collections. Sparrow Solitaire could be considered the culmination of all of this exploration and gathered knowledge presented in a single game.&lt;/p&gt;

&lt;p&gt;Once I got hold of a Playdate I started thinking about implementation details. Coding prototypes, figuring out sizes, textures, shadows, frame rate, tricks, optimisations, but with no particular game in mind. Just sailing free across a sea of ideas.&lt;/p&gt;

&lt;p&gt;I struck upon a novel way to generate patterns of dots. Instead of using organised Beyer dither patterns, I used error diffusion dithering and fed it a solid colour. When a shade of grey is run through Burkes dithering algorithm it produces organic-looking patterns of dots that are ever so pleasing to the eye. Interestingly, other dithering algorithms don’t exhibit the same result. This image became a catalyst and the core of Sparrow Solitaire.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-release-dots.png&quot; alt=&quot;PNG&quot; title=&quot;A shade of grey fed into the &amp;lt;em&amp;gt;Burkes&amp;lt;/em&amp;gt; dithering algorithm&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After this I drew the traditional Chinese mahjong tile set, and figured out a tile size that would allow the standard Mahjong Solitaire layouts to fit fully on screen. Unlike the PLATO and Macintosh games, which used border thickness to denote the height of a tile in the layout, I offset the tiles in a sort of isometric view and added a repeating shadow dither pattern. After this I drew regional variations for Japan, Europe and America. I drew tile sets inspired by the original late-90s Japanese Emoji set, others based on Egyptian and Toki Pona heiroglyphs, and an alphanumeric tile set I thought might be easiest for newcomers. I even recorded sounds of my own mahjong tiles.&lt;/p&gt;

&lt;h2 id=&quot;sunset&quot;&gt;Sunset&lt;/h2&gt;

&lt;p&gt;I found (and promptly forgot about until just now!) royalty free sound effects of sparrows, rain, button presses, confirmation tones. During all of this, amongst my normal music listening, I stumbled across a song that I thought sounded really great: it was the track &lt;a href=&quot;https://soundcloud.com/iiyume/starry-dish&quot;&gt;“Starry Dish” by Yuyake Monster&lt;/a&gt; a Japanese music producer. The track is a sort of bouncy low-fi video-game hip-hop and piano thing. I wanted to hear more by this musician, so I clicked on their profile and listened to the next track. It was “Herbal Remedies” and I liked it even more! It featured plucked strings and a melodic bass line and… about half way through… bird song! And these tunes were already tagged as royalty free, so it was meant to be. When I reached out to Yuyake Monster they were super happy to have their music used in a game.&lt;/p&gt;

&lt;p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allow=&quot;autoplay&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F946034860&amp;amp;auto_play=false&amp;amp;show_artwork=true&amp;amp;visual=true&quot;&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It was at this point that I released a prototype with graphics, sounds and animation of the layout dealing. I quickly realised that it would take a lot of time and effort to finish the game, so I made the difficult decision to abandon it. But work resumed later on with the help of &lt;a href=&quot;https://twitter.com/vogelscript&quot;&gt;Mac Vogelsang&lt;/a&gt;, as you can read about in &lt;a href=&quot;/2022/07/13/sparrow-solitaire-for-playdate/&quot;&gt;my earlier blog post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;one-vision&quot;&gt;One vision&lt;/h2&gt;

&lt;p&gt;Mac had taken on the majority of the programming, slowly eroding what remained of my prototype code and refactoring things into a more solid foundation. I was concentrating on graphics and animation. We shared game design decisions. By this point we had both played a ton of mahjong solitaire games from the original Shanghai on Macintosh, through versions on almost every home console, handheld and home computer platform, to versions on the latest Nintendo consoles. We had a thorough understanding of things that worked well with a mouse, what did not work so well with a game controller, what worked best on screen and what limitations these old platforms imposed on the games.&lt;/p&gt;

&lt;p&gt;Comparing Playdate to the best handhelds from the 90s it became obvious that we were working with a much more capable device, in terms of both CPU power and graphical fidelity. We could lean into the strengths of the device and provide a tailored experience that made use of the Playdate’s unique control mechanism - the crank - as well as its excellent sound and graphics hardware. I hope Mac will write more about getting the most out of the device, writing code that made the most of Playdate performance to do things that have never been done before in a mahjong solitaire game. Sparrow Solitaire has truly ground-breaking features some of which are only possible on Playdate.&lt;/p&gt;

&lt;p&gt;Meanwhile, with the prompting and encouragement of Mac, I researched classic Chinese and Japanese painting techniques and drew some Eurasian tree sparrows and cherry blossom in the classic ink and watercolour style.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-release-strokes.png&quot; alt=&quot;PNG&quot; title=&quot;Vector drawings of tree sparrow and blossom, using only strokes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These illustrations were used to create the game’s launch animation. I started to create the animation the traditional way, but quickly changed tact and created it programatically instead.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-release-launch.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;content-matters&quot;&gt;Content matters&lt;/h2&gt;

&lt;p&gt;For the full version of the game I created additional backgrounds, cursors, grids, animations, tools to aid development and more besides. I created several fonts, all carefully kerned and tweaked to look their best on the Playdate. I’d &lt;a href=&quot;/2020/10/03/found-whilst-backing-up-an-old-pc/&quot;&gt;created a popular font in my teens&lt;/a&gt; and it was fun to get back to that. More backgrounds, more tile sets including my favourite “zen”. Even now, when I see this tile set in the game, I often shake my head in disbelief. How was I capable of drawing these symbols so well at such a small size? My &lt;a href=&quot;https://www.youtube.com/watch?v=y4-2iTJW-2Y&quot;&gt;Susan Kare&lt;/a&gt; moment, if you will. If ever there was a lesson that you should believe in your own abilities, this was it for me.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-release-zen.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;hidden-in-plain-sight&quot;&gt;Hidden in plain sight&lt;/h2&gt;

&lt;p&gt;The influence of the Macintosh and the nostalgia in the final look and feel of the game is something I wear proudly. Sparrow Solitaire is the sum total of all my passions and interests, wrapped up in a neat little game that will provide hundreds of hours of fun and relaxation.&lt;/p&gt;

&lt;p&gt;But what about if you look a little deeper? You will find brush/fill patterns from &lt;a href=&quot;https://en.wikipedia.org/wiki/MacPaint&quot;&gt;MacPaint&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Atkinson_dithering&quot;&gt;Atkinson dithering&lt;/a&gt; as first seen in ThunderScan, elements drawn in &lt;a href=&quot;/2021/04/06/ultrapaint-manual/&quot;&gt;UltraPaint&lt;/a&gt;, pixels generated using &lt;a href=&quot;https://en.wikipedia.org/wiki/Dave_Theurer&quot;&gt;DeBabelizer&lt;/a&gt;, and so much more. Heck, we even use &lt;a href=&quot;https://en.wikipedia.org/wiki/Garamond&quot;&gt;Garamond&lt;/a&gt; as our brand typeface which is the same one Apple used in their classic Macintosh advertising, the most well known of which is the “Think different” campaign. Sparrow Solitaire is my love letter to the Macintosh, but runs on a device that fits in the palm of your hand.&lt;/p&gt;

&lt;p&gt;One of my favourite “&lt;a href=&quot;https://en.wikipedia.org/wiki/Easter_egg_(media)&quot;&gt;Easter Eggs&lt;/a&gt;” in Sparrow Solitaire is some clip art from the &lt;a href=&quot;https://macintoshgarden.org/author/enzan-hoshigumi-co&quot;&gt;Scroll collections&lt;/a&gt;, published in 1986/87 by Japanese Macintosh specialists Enzan-Hoshigumi. Specifically I have used a border for the manual/credits overlay, and several sections of artwork for our patterned backgrounds. These sections of artwork were not bundled as brushes/fills, but are nevertheless easy to cut out and use as a repeating fill in an image editor. They are based on repeating elements that are much larger than the 16x16 pixel patterns of MacPaint, so they allow for patterns that are not as garish and easier on the eyes. Plus, I love the fact that in 2023 Enzan-Hoshigumi finally have their first video game credit, almost &lt;a href=&quot;/2021/12/16/tomoya-ikeda-macintosh-artist/&quot;&gt;40 years after working on their first video game&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-release-enzan-hoshigumi.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-great-wave-of-mahjong&quot;&gt;The Great Wave of Mahjong&lt;/h2&gt;

&lt;p&gt;Finally, to come full circle back to the image seen in the trailer at the top of the page: “The Great Wave of Mahjong”. I came up with the concept for the image and commissioned the wonderful &lt;a href=&quot;https://www.instagram.com/vxclhd/&quot;&gt;Vxcl&lt;/a&gt; to create it, leaving them free to interpret the brief. They pretty much nailed it first time, and there were only a handful of small notes from me - in the form of &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1646262994727321602?s=20&quot;&gt;screen grabs with coloured highlighter markup&lt;/a&gt; - to tweak the alignment of details of a few elements. This is the &lt;a href=&quot;/2021/08/23/daily-driver-teaser-artwork/&quot;&gt;second such render&lt;/a&gt; I’ve commissioned, a look inspired by 1980s Japanese PC/game mags.&lt;/p&gt;

&lt;p&gt;You can download a high resolution version of this image at &lt;a href=&quot;https://vogelscript.itch.io/sparrow-solitaire&quot;&gt;itch.io&lt;/a&gt; to use as PC/phone wallpaper.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/great-wave-of-mahjong-by-vxcl.jpg&quot; alt=&quot;JPG&quot; title=&quot;&amp;lt;em&amp;gt;&amp;#x201C;The Great Wave of Mahjong&amp;#x201D;&amp;lt;/em&amp;gt;, by Vxcl&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;update&quot;&gt;Update!&lt;/h2&gt;

&lt;p&gt;Less than two weeks after version 1.0 we released an update to address a few small issues and add a bunch more content! It features dynamic weather effects, three new tile sets and more cool stuff. You can &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1649809550239846405&quot;&gt;read about version 1.1 in this Twitter thread&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;elsewhere&quot;&gt;Elsewhere&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;2024-03-08—&lt;a href=&quot;https://play.date/games/community-awards-2023/&quot;&gt;Playdate Community Awards 2023: Best Puzzle Game&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 13 Apr 2023 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2023/04/13/sparrow-solitaire-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2023/04/13/sparrow-solitaire-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Sparrow Solitaire for Playdate (Early Access)</title>
          <description>&lt;p&gt;This post is a history of Sparrow Solitaire, my latest game for Playdate. It started out as a prototype and was later taken on by Mac Vogelsang. We’re working together to make the best ever mahjong solitaire game.&lt;/p&gt;

&lt;h3 id=&quot;2021-january-10th&quot;&gt;2021, January 10th&lt;/h3&gt;
&lt;p&gt;I’m really into Hanafuda (Japanese flower cards) and found that the 1991 Macintosh game Shanghai featured tiles based on Hanafuda. I booted it up &lt;a href=&quot;https://archive.org/details/ShanghaiIIDragonsEye&quot;&gt;at Internet Archive&lt;/a&gt; and had a quick play.&lt;/p&gt;

&lt;p&gt;For the next week or so I went down the Shanghai rabbit hole. Its history is &lt;a href=&quot;http://home.halden.net/vkp/vkp/origin.html&quot;&gt;quite interesting&lt;/a&gt; and fraught with drama so I won’t repeat it here.&lt;/p&gt;

&lt;h3 id=&quot;2021-january-19th&quot;&gt;2021, January 19th&lt;/h3&gt;

&lt;p&gt;This is the date on the first screenshot I captured of my prototype mahjong solitaire game for Playdate.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-early-1.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I tested different size tiles until I found the sweet spot that could fit a whole layout on the Playdate’s 400x240 screen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-early-2.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The following day I drew a set of tiles and it started to look like a real game! I called it &lt;em&gt;Sparrow Solitaire&lt;/em&gt; because the sound of mahjong tiles rubbing together is said to sound like sparrows chirping. In fact, the original Chinese name for mahjong reused the word for sparrow. So this thing had a name at least!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-my-tiles.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I spent the next month or so, on-and-off, programming object-oriented Lua to manage the game state, tiles, layout, dealing, sound effects and I drew a handful more tile sets.&lt;/p&gt;

&lt;p&gt;Daily Driver was my focus and this little puzzle game was supposed to be a short palate cleanser to keep things interesting. When it turned out to be more involved I lost momentum and abandoned it. My todo list at that time was as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Todo
[ ] calc free data per half position
[ ] sound based on free data
[ ] controls to move prev/next tiles
[ ] controls to select tiles
[ ] match tiles
[ ] face down all tiles
[ ] face up free tiles
[ ] editor
[ ] optimise animations

Done
[X] sound effects
[X] define layouts to fill screen
[X] animate tiles
[X] multi-dimension array (as autotable)
[X] ability to reinit table
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What an optimistically short set of todo items! That’s game programmers for you.&lt;/p&gt;

&lt;h3 id=&quot;2022-april-15th&quot;&gt;2022, April 15th&lt;/h3&gt;

&lt;p&gt;When Playdate launched I bundled the game in my pack of Prototypes and tried to forget about it.&lt;/p&gt;

&lt;h3 id=&quot;2022-may-12th&quot;&gt;2022, May 12th&lt;/h3&gt;

&lt;p&gt;I couldn’t stop thinking about the game and it seemed a shame that I had put so much effort into it and then abandoned it. But I’m a realist and I knew that I would never finish it myself. So I thought it would be fun to offer it out to any interested developers and see if they wanted to finish it. No replies to &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1524724007827914752&quot;&gt;this tweet&lt;/a&gt;, but the same message on the Playdate Squad Discord server had some responses. I decided to hand over to Mac Vogelsang (&lt;a href=&quot;https://twitter.com/vogelscript&quot;&gt;@vogelscript&lt;/a&gt;) as I had really enjoyed his Bird and Beans game. So a few days later he began work “finishing off” my programming. What an understatement.&lt;/p&gt;

&lt;h3 id=&quot;2022-july-13th&quot;&gt;2022, July 13th&lt;/h3&gt;

&lt;p&gt;For the last two months Mac has worked his magic on the game and I’ve tagged along for the ride. Having worked on my own for so long I wondered what it would be like working with somebody else. It was more fun and productive than I ever could have expected! Mac brought the best out of me, pushing me to achieve better results than I would have otherwise been happy with. Mac also pushed himself, creating what I believe to be a world-first method of cursor control in a mahjong solitaire game, made possible by two properties of Playdate: its fast processing speed and its lack of touch screen!&lt;/p&gt;

&lt;p&gt;Out of this partnership not only comes a great game, but some new offshoot projects like an Animation tool (from me), a board game (from Mac), and a Game Options class (Mac’s magic reworking of one of my old classes) and several new fonts some of which are used in Sparrow Solitaire. These projects should all release in the near future.&lt;/p&gt;

&lt;p&gt;At this point Sparrow Solitaire is really Mac’s game, albeit one that happens to have my graphics and some of my programming DNA in it, so it’s fitting that it will live on his itch.io page.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-game.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;launch-animation&quot;&gt;Launch Animation&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/sparrow-launch.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;download&quot;&gt;Download&lt;/h2&gt;

&lt;p&gt;Update, April 2023: the full version of Sparrow Solitaire for Playdate is &lt;a href=&quot;https://vogelscript.itch.io/sparrow-solitaire&quot;&gt;available now on itch.io&lt;/a&gt; and you can also &lt;a href=&quot;https://vogelscript.itch.io/sparrow-solitaire/devlog/515286/sparrow-solitaire-v10&quot;&gt;read about what to went into the full game&lt;/a&gt;.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2022/07/13/sparrow-solitaire-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2022/07/13/sparrow-solitaire-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Circular for Playdate</title>
          <description>&lt;p&gt;This concept was a typical prototype: the core action came together quickly but then making that into a game took a while.&lt;/p&gt;

&lt;p&gt;At some point soon I’ll write a devlog about the problems, solutions, questions and answers involved in its development.&lt;/p&gt;

&lt;p&gt;I’m really proud of this little gem. It’s my first time putting a lot of effort into score balancing in the style of my favourite Japanese arcade games, and I hope you have fun trying to reach 1 million points. There are sure to be some surprises along the way.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/circular-game.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;download&quot;&gt;Download&lt;/h2&gt;

&lt;p&gt;Circular for Playdate is &lt;a href=&quot;https://gingerbeardman.itch.io/circular&quot;&gt;available now on itch.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 30 May 2022 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2022/05/30/circular-for-playdate/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2022/05/30/circular-for-playdate/</guid>
        </item>
      
    
      
        <item>
          <title>Wire Hang Redux for 64-bit macOS</title>
          <description>&lt;p&gt;I just uploaded a 64-bit macOS version of my 2004 game &lt;a href=&quot;/2004/06/20/wire-hang-redux/&quot;&gt;Wire Hang Redux&lt;/a&gt; that I had forgotten all about. So now you can play it on your 64-bit Mac. This version built using BlitzMax. I’ll try to build it for Apple Silicon some time this decade, but no promises!&lt;/p&gt;

&lt;p&gt;Read more about the game in the original &lt;a href=&quot;/2004/06/20/wire-hang-redux/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://gingerbeardman.itch.io/wire-hang-redux&quot;&gt;gingerbeardman.itch.io/wire-hang-redux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-title.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-clouds.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-stars.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 23 Apr 2022 15:40:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2022/04/23/wire-hang-redux-for-64-bit-macos/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2022/04/23/wire-hang-redux-for-64-bit-macos/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Club GTi</title>
          <description>&lt;p&gt;My &lt;a href=&quot;/2023/06/07/gti-cub-supermini-festa/&quot;&gt;GTi Club: Supermini Festa!&lt;/a&gt; obsession has bled into my game &lt;a href=&quot;/tag/dailydriver/&quot;&gt;Daily Driver&lt;/a&gt;… the “Club GTi” car features smaller wheels than the standard size, more roll during turning, and lots of detail and decoration to show off the rendering workflow I spent so many hours on. A good choice for the autotesting/motorkhana/gymkhana stages.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-club-gti.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s the 3D model, created in &lt;a href=&quot;https://openscad.org&quot;&gt;OpenSCAD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-club-gti-model.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 08 Mar 2022 12:32:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2022/03/08/club-gti/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2022/03/08/club-gti/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Teaser Artwork</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-artwork.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I commissioned the talented &lt;a href=&quot;https://www.instagram.com/vxclhd/&quot;&gt;@vxclhd&lt;/a&gt; to create a clay-style diorama of Daily Driver!&lt;/p&gt;

&lt;p&gt;There are a few things in this scene that I’ve not yet shown in game footage. Imagine this is a box shot teaser in a game magazine, while you wait for the Playdate and its game to release.&lt;/p&gt;

&lt;p&gt;“Please understand”, as Satoru Iwata used to say.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-conversation=&quot;none&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;It&amp;#39;s inspired by a style of plasticine modelling I often see in old 1980s Japanese computer/games promotional art. &lt;br /&gt;&lt;br /&gt;Examples that come to mind: box art on some of the Fujitsu FM-Towns Free Software Collection and select covers of MSX•FAN, but there are too many to mention. &lt;a href=&quot;https://t.co/aAdSEVL4yA&quot;&gt;pic.twitter.com/aAdSEVL4yA&lt;/a&gt;&lt;/p&gt;&amp;mdash; Matt Sephton🎴 (@gingerbeardman) &lt;a href=&quot;https://twitter.com/gingerbeardman/status/1428772256239476740?ref_src=twsrc%5Etfw&quot;&gt;August 20, 2021&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 23 Aug 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/08/23/daily-driver-teaser-artwork/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/08/23/daily-driver-teaser-artwork/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: How big is a sprite sheet?</title>
          <description>&lt;p&gt;Since the early days of the project I’ve been generating the car sprites by rotating the 3D model 360 degrees in a sequence of 32 steps. It works well and I hadn’t given it much thought. Until over on the &lt;a href=&quot;https://discord.gg/zFKagQ2&quot;&gt;unofficial Playdate Discord server&lt;/a&gt; user Jono showed of a hot-dog trick rendered using 64 steps which looked super smooth! This got me thinking about increasing the number of rotation steps used in my workflow for Daily Driver.&lt;/p&gt;

&lt;h2 id=&quot;code-changes&quot;&gt;Code changes&lt;/h2&gt;

&lt;p&gt;I had to do a bit of code changing as I had used the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32&lt;/code&gt;, or the angular equivalent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.25&lt;/code&gt; (degrees), in a few places throughout my code. Once I’d changed those to refer to a single variable I was set. I can now run the game with sprites of any number of steps.&lt;/p&gt;

&lt;h2 id=&quot;rendering-changes&quot;&gt;Rendering changes&lt;/h2&gt;

&lt;p&gt;Similar changes were also needed in my rendering workflow, moving any hardcoded steps or angle values into a variable. After replacing hard-coded magic numbers with variables, I spent way too long figuring out why angles were being rounded down to the nearest integer. Eventually I realised that in shell scripts the calculation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$( 360/64 )&lt;/code&gt; gives an integer result of 5, whereas  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$( 360.0/64 )&lt;/code&gt; gives the more accurate floating point result of 5.625.&lt;/p&gt;

&lt;p&gt;Interestingly, I also needed to increase my filename pattern from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%03d&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%04d&lt;/code&gt; as there are now thousands of images being processed.&lt;/p&gt;

&lt;h2 id=&quot;how-high&quot;&gt;How high?&lt;/h2&gt;

&lt;p&gt;After making the necessary changes to my workflow it is very easy to render a new set of sprites. But what number of steps to use? My immediate thought was to simply double it to 64, which is higher than the frame rate I’m using and the result was definitely smoother.&lt;/p&gt;

&lt;p&gt;After this &lt;a href=&quot;https://twitter.com/mrgan&quot;&gt;Neven Mrgan&lt;/a&gt; asked if I’d explored whether there was a performance limit or upper boundary? I hadn’t but it sounded like a fun thing to explore.&lt;/p&gt;

&lt;p&gt;But why go higher? Well, even if we have more frames of animation that than refresh rate, we can still gain in terms of accuracy. The more steps there are the more discrete angles we can show the car pointing. That was good enough reason for me to try it out.&lt;/p&gt;

&lt;p&gt;I spent some time exporting a sprite at 32, 64, 90, 128, 180, 256, 360-steps to compare not only the smoothness of the animation but also other related implications.&lt;/p&gt;

&lt;h2 id=&quot;selected-results&quot;&gt;Selected results&lt;/h2&gt;

&lt;p&gt;Most modern browsers are well-behaved enough to only play an Animated GIF if it is on the page. So you’ll probably need to force reload the page (hold shift and click reload) to synchronise one or more of the below animations.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-32.gif#playdate&quot; alt=&quot;32 rotation steps&quot; title=&quot;Above: 32 rotation steps. After I&apos;ve mentioned looking for the &amp;quot;judder&amp;quot; you won&apos;t be able to unsee it&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-64.gif#playdate&quot; alt=&quot;64 rotation steps&quot; title=&quot;Above: Even with twice as many rotation steps there&apos;s still a slight judder&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-90.gif#playdate&quot; alt=&quot;90 rotation steps&quot; title=&quot;Above: 90 rotation steps give us one sprite every 4 degrees, judder becomes less noticable&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-180.gif#playdate&quot; alt=&quot;180 rotation steps&quot; title=&quot;Above: 180 rotation steps give us one sprite every 2 degrees, judder is even less noticable&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-360.gif#playdate&quot; alt=&quot;360 rotation steps&quot; title=&quot;Above: 360 rotation steps give us one sprite for every degree, as good as it gets&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;stats&quot;&gt;Stats&lt;/h2&gt;

&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;steps #&lt;/th&gt;
        &lt;th&gt;render time Secs&lt;/th&gt;
        &lt;th&gt;frames #&lt;/th&gt;
        &lt;th&gt;width PX&lt;/th&gt;
        &lt;th&gt;pixels W×H&lt;/th&gt;
        &lt;th&gt;png KB&lt;/th&gt;
        &lt;th&gt;pdt KB&lt;/th&gt;
        &lt;th&gt;ram Bytes&lt;/th&gt;
        &lt;th&gt;ram MB&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;32&lt;/td&gt;
        &lt;td&gt;30s&lt;/td&gt;
        &lt;td&gt;704&lt;/td&gt;
        &lt;td&gt;1216&lt;/td&gt;
        &lt;td&gt;1016576&lt;/td&gt;
        &lt;td&gt;48&lt;/td&gt;
        &lt;td&gt;39&lt;/td&gt;
        &lt;td&gt;147404&lt;/td&gt;
        &lt;td&gt;0.15&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;64&lt;/td&gt;
        &lt;td&gt;59s&lt;/td&gt;
        &lt;td&gt;1408&lt;/td&gt;
        &lt;td&gt;2432&lt;/td&gt;
        &lt;td&gt;2033152&lt;/td&gt;
        &lt;td&gt;64&lt;/td&gt;
        &lt;td&gt;78&lt;/td&gt;
        &lt;td&gt;294807&lt;/td&gt;
        &lt;td&gt;0.29&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;90&lt;/td&gt;
        &lt;td&gt;82s&lt;/td&gt;
        &lt;td&gt;1980&lt;/td&gt;
        &lt;td&gt;3420&lt;/td&gt;
        &lt;td&gt;2859120&lt;/td&gt;
        &lt;td&gt;111&lt;/td&gt;
        &lt;td&gt;107&lt;/td&gt;
        &lt;td&gt;414572&lt;/td&gt;
        &lt;td&gt;0.41&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;128&lt;/td&gt;
        &lt;td&gt;114s&lt;/td&gt;
        &lt;td&gt;2816&lt;/td&gt;
        &lt;td&gt;4864&lt;/td&gt;
        &lt;td&gt;4066304&lt;/td&gt;
        &lt;td&gt;143&lt;/td&gt;
        &lt;td&gt;140&lt;/td&gt;
        &lt;td&gt;589614&lt;/td&gt;
        &lt;td&gt;0.59&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;180&lt;/td&gt;
        &lt;td&gt;159s&lt;/td&gt;
        &lt;td&gt;3960&lt;/td&gt;
        &lt;td&gt;6840&lt;/td&gt;
        &lt;td&gt;5718240&lt;/td&gt;
        &lt;td&gt;174&lt;/td&gt;
        &lt;td&gt;188&lt;/td&gt;
        &lt;td&gt;829145&lt;/td&gt;
        &lt;td&gt;0.83&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;256&lt;/td&gt;
        &lt;td&gt;192s&lt;/td&gt;
        &lt;td&gt;5632&lt;/td&gt;
        &lt;td&gt;9728&lt;/td&gt;
        &lt;td&gt;8132608&lt;/td&gt;
        &lt;td&gt;209&lt;/td&gt;
        &lt;td&gt;227&lt;/td&gt;
        &lt;td&gt;1179228&lt;/td&gt;
        &lt;td&gt;1.18&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;360&lt;/td&gt;
        &lt;td&gt;285s&lt;/td&gt;
        &lt;td&gt;7920&lt;/td&gt;
        &lt;td&gt;13680&lt;/td&gt;
        &lt;td&gt;11436480&lt;/td&gt;
        &lt;td&gt;240&lt;/td&gt;
        &lt;td&gt;264&lt;/td&gt;
        &lt;td&gt;1658290&lt;/td&gt;
        &lt;td&gt;1.66&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;

&lt;h2 id=&quot;charts&quot;&gt;Charts&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rotation-steps-charts.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;implications&quot;&gt;Implications&lt;/h2&gt;

&lt;p&gt;The increase from 32-steps to 360-steps is echoed by an increase of around a factor of ten across each of rendering time, number of frames and memory usage.&lt;/p&gt;

&lt;p&gt;In the above table we can see that related stats increase pretty much linearly, with a slight downward trend for file sizes and a slight upward trend for everything else.&lt;/p&gt;

&lt;p&gt;The increased smoothness is great, and very easy to notice. The benefits of the increased smoothness becomes less noticeable with each increase in step count. However, it’s important to remember there are other implications:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Rendering time&lt;/li&gt;
  &lt;li&gt;File size&lt;/li&gt;
  &lt;li&gt;Memory usage&lt;/li&gt;
  &lt;li&gt;Performance in-game&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;rendering-time&quot;&gt;Rendering time&lt;/h3&gt;
&lt;p&gt;This increases from what I would call a quick 30 seconds per render at 32-steps, to an extremely slow 284 seconds (4m45s) at 360-steps. For a full set of renders it’s not as easy as multiplying that number, there is some overhead that goes with it. This means a real world increase from ~20 minutes to multiple hours, which could be a problem. Cars aren’t generally re-rendered very frequently but when I do render them I do it many times as I make minor tweaks. So, at this point all numbers of steps are on the table but with a preference for those with shorter rendering times.&lt;/p&gt;

&lt;h3 id=&quot;file-size&quot;&gt;File size&lt;/h3&gt;
&lt;p&gt;Playdate’s compiled image format is very similar in file size to an optimised PNG. The file size increases by slightly more than double as the number of steps is doubled. Even the largest size at 360-steps is only 264KB (0.26MB) which seems OK in the grand scheme of things. All numbers of steps are on the table.&lt;/p&gt;

&lt;h3 id=&quot;memory-usage&quot;&gt;Memory usage&lt;/h3&gt;
&lt;p&gt;As we can see by the table below, memory usage is quite optimised on Playdate. The system is clever enough to trim transparent areas from cells of sprite sheets and store the offset of the image instead of the complete raw bitmap data. For this example sprite memory usage is roughly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(W×H÷8)*1.16&lt;/code&gt; rather than the expected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(W×H÷8)*2.0&lt;/code&gt;. The car sprite is my largest occupier of memory. Only one is loaded at a time and even at 360-steps it fits comfortably in the Playdate’s 16MB RAM. All numbers of steps are on the table.&lt;/p&gt;

&lt;h3 id=&quot;performance-in-game&quot;&gt;Performance in-game&lt;/h3&gt;
&lt;p&gt;I’m targeting a refresh rate of 60fps on the device, so it’s important for me to check that any changes to rendering don’t have an adverse effect on performance. At 32-steps the car sprite was changed roughly every second update, with 64-steps and higher the car sprite will be changed every update. Looking at performance in broad terms, there does seem to be a small hit when using the large numbers of steps. It doesn’t prevent me hitting 60fps, but it does leave me less time to do other things I have planned.&lt;/p&gt;

&lt;h2 id=&quot;final-choice&quot;&gt;Final choice?&lt;/h2&gt;
&lt;p&gt;If you’ve read this far you’re probably wanting to know my choice. How many steps did I choose? Well, the jury is out. This is the sort of thing I’ll have to live with for a while before I settle on a choice.&lt;/p&gt;

&lt;p&gt;I’ll probably end up going somewhere in the middle with a choice that gives increased smoothness and accuracy, renders fairly quickly and doesn’t affect performance in-game.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 07 Aug 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/08/07/how-big-is-a-sprite-sheet/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/08/07/how-big-is-a-sprite-sheet/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: To GIF and Back</title>
          <description>&lt;p&gt;When rendering my vehicles I generate a single PNG containing all frames. Playdate SDK calls these image tables, or more specifically matrix image tables. You could also call them sprite-sheets, with the one qualification that every sprite has the same dimensions.&lt;/p&gt;

&lt;p&gt;Given that these are plain old images they can be viewed easily. Showing a grid on top of the image makes the layout obvious. You can edit the image as a whole easily enough, but what if you want to adjust the size of every cell? Then we have a problem.&lt;/p&gt;

&lt;p&gt;There are a few apps that can load image tables, asking for the cell size during loading. My favourite such app is &lt;a href=&quot;https://www.piskelapp.com&quot;&gt;Piskel&lt;/a&gt; which has good options for import, editing, and export.&lt;/p&gt;

&lt;p&gt;However there is another type of image that consists of multiple frames of the same dimensions: the Animated GIF. There are far more apps that can deal with this format, such as Acorn or Adobe Photoshop.&lt;/p&gt;

&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;/h2&gt;

&lt;p&gt;How can we convert a matrix image table to Animated GIF, and back again?&lt;/p&gt;

&lt;h2 id=&quot;thinking&quot;&gt;Thinking&lt;/h2&gt;

&lt;p&gt;We could use Piskel, but its GUI isn’t the most straightforward so using it twice at separate points in the conversion process gets old fast.&lt;/p&gt;

&lt;p&gt;So I had the idea of writing a couple of small shell scripts that leverage imagemagick and can be run from my Makefile, the command-line, macOS context menu, or all of the above.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;Below are both scripts, be sure to grab the Gist versions as they have error checking and “help” usage display.&lt;/p&gt;

&lt;h3 id=&quot;convert-image-table-to-animated-gif&quot;&gt;Convert image table to Animated GIF&lt;/h3&gt;

&lt;noscript&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/b85367a8e6b3d139d9c85f49e146af38&quot;&gt;View the source code as a Gist&lt;/a&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/gingerbeardman/b85367a8e6b3d139d9c85f49e146af38.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;convert-animated-gif-to-image-table&quot;&gt;Convert Animated GIF to image table&lt;/h3&gt;

&lt;noscript&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/15a8e1e72745848190c0e7d583ca24e1&quot;&gt;View the source code as a Gist&lt;/a&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/gingerbeardman/15a8e1e72745848190c0e7d583ca24e1.js&quot;&gt;&lt;/script&gt;

</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 14 Jul 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/07/14/image-table-animated-gif/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/07/14/image-table-animated-gif/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Teaser Trailer</title>
          <description>&lt;p&gt;To celebrate today’s Playdate update video here is a Daily Driver teaser trailer. Yay!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-teaser-trailer.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 08 Jun 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/06/08/teaser-trailer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/06/08/teaser-trailer/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Channelling RGB into 1-bit</title>
          <description>&lt;p&gt;After successfully splitting out dark and light elements of the sprites and rendering them in a HDR style, I figured: why stop there? Maybe I could squeeze another colour into the render - some specific shade of grey - that I could treat in a different way to introduce dithered areas to the sprite.&lt;/p&gt;

&lt;p&gt;This came together very quickly but it resulted in my Makefile, yet again, becoming too complicated. So I decided to rethink my approach.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit.gif&quot; alt=&quot;GIF&quot; title=&quot;Dither layer: specifying areas that should have a dither pattern applied, here the rear grille&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If only there was a way to encode information about three different colours in a single bitmap image. Hang on a minute, there already is: RGB!&lt;/p&gt;

&lt;h2 id=&quot;channels&quot;&gt;Channels&lt;/h2&gt;

&lt;p&gt;So my new idea was to use red, green and blue as the colours for my render, then split the image into those colour channels and process each individually to get separate light, dark and dithered elements.&lt;/p&gt;

&lt;p&gt;Using imagemagick it is easy to separate a single channel from an image:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;magick render.png -channel G -separate green.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From this simple start things quickly become more complex. I always find building imagemagick commands a very time consuming process. Indeed, it took me a long time to arrive at a workflow that was just right. But I think of it as time well-spent as it will result in much quicker and easier iterations when designing vehicles.&lt;/p&gt;

&lt;p&gt;Overall, I did a few more tricks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;threshold convert the channels to 1-bit colour&lt;/li&gt;
  &lt;li&gt;apply a dither pattern to the green channel&lt;/li&gt;
  &lt;li&gt;composite select layers back together as the final image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the process worked a treat!&lt;/p&gt;

&lt;p&gt;The resulting workflow takes half as long to execute as my previous workflow, with all vehicles rendering in ~8 minutes compared to ~16 minutes before that.&lt;/p&gt;

&lt;p&gt;Here are some example hi-res images showing the journey from initial render to final composite:&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-1-render.png&quot; alt=&quot;PNG&quot; title=&quot;Render, 8-bit colour&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-2-red.png&quot; alt=&quot;PNG&quot; title=&quot;Red channel, inverted, 1-bit colour&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-3-green.png&quot; alt=&quot;PNG&quot; title=&quot;Green channel, 1-bit colour&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-4-blue.png&quot; alt=&quot;PNG&quot; title=&quot;Blue channel, 1-bit colour&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-5-alpha.png&quot; alt=&quot;PNG&quot; title=&quot;Alpha channel, 1-bit colour&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-6-dither.png&quot; alt=&quot;PNG&quot; title=&quot;Green channel with Dither pattern applied&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-rgb-1bit-7-composite.png&quot; alt=&quot;PNG&quot; title=&quot;Final composite, 1-bit colour&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;elsewhere&quot;&gt;Elsewhere&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;2021-06-06—&lt;a href=&quot;https://news.ycombinator.com/item?id=27409371&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 05 Jun 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/06/05/channelling-rgb-into-1bit/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/06/05/channelling-rgb-into-1bit/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Pseudo-HDR</title>
          <description>&lt;p&gt;I love OpenSCAD “the programmer’s solid 3D CAD modeller”, despite its idiosyncrasies. One of the quirks that causes me most pain is the lack of controls for scene lighting in the Preview render. Unfortunately, I use that very Preview render as my main output!&lt;/p&gt;

&lt;p&gt;This lighting issue manifests as shadows cast on the model. As I rotate the car some white “highlight” elements become darker. At this point the model is made up of many more shades of grey than I’d like.&lt;/p&gt;

&lt;p&gt;The problem escalates when I take the Preview renders and convert them to 1-bit (black and white) ready for display on Playdate. I use a simple threshold conversion where any pixels darker than the threshold value become black, and any lighter become white. The highlight elements that have been cast in shadow are now grey and in many cases after the threshold conversion they end up as black pixels when they should be white. The net visual result is a loss of detail as well as flashing elements as they disappearing on certain frames.&lt;/p&gt;

&lt;p&gt;My first attempt at solving this problem was to set model-specific threshold levels. This worked to a degree but there were still elements that would flash on and off as the car rotated, with headlights being the most noticeable. Whilst I lived with the issue for a long time it always bothered me as it did make the sprite feel buggy. Deep down I knew that the results could be better. However, looking at the OpenSCAD development roadmap made it clear that any improvements would have to come from me.&lt;/p&gt;

&lt;p&gt;One day, out of the blue, I realised that if black pixels are more reliably rendered then why don’t I take advantage of that and render the model in opposite colours so that the highlights are now black. After rendering I could simply negate the colours in the resulting image and the highlights would become white again. I tried a quick test and the results were good!&lt;/p&gt;

&lt;p&gt;Of course this means an additional render stage is added to my workflow, but that’s of little consequence since the Makefile is doing all the hard work. I also had to make some changes to my render scripts so that the normal and negative images are composited together into the final image. The resulting sprites have no flashing elements, maintain more fine detail, and appear a lot more solid as a result. Excellent!&lt;/p&gt;

&lt;p&gt;Afterwards it struck me that this process is similar to HDR photography where multiple photographs are combined to increase the dynamic range in the final image. So, just for kicks, I’m referring to this technique as HDR 1-bit rendering.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-sprites-old.gif&quot; alt=&quot;GIF&quot; title=&quot;Old rendering workflow: note the disappearing headlights&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-sprites-new.gif&quot; alt=&quot;GIF&quot; title=&quot;New rendering workflow: headlights are present and correct&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 21 May 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/05/21/pseudo-hdr/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/05/21/pseudo-hdr/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Makefile</title>
          <description>&lt;p&gt;During the shadow rendering changes I was generating new sprites quite frequently, and I quickly realised that my mess of shell scripts just wasn’t a good enough system to be used in anger. I would have to call my scripts manually, with a variety of parameters, and remember a bunch of stuff unique to each script.&lt;/p&gt;

&lt;p&gt;So I spent a day converting the script system into a Makefile, with rules for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rendering&lt;/li&gt;
  &lt;li&gt;stitching&lt;/li&gt;
  &lt;li&gt;post-processing&lt;/li&gt;
  &lt;li&gt;copying&lt;/li&gt;
  &lt;li&gt;cleaning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also improved the scripts to make them touch all their output files with the last-modified timestamp of the original 3D model, meaning the scripts could become self-aware and know which output files are up-to-date and which need re-rendering.&lt;/p&gt;

&lt;p&gt;With this system I can generate a full set of renders of all vehicles in ~minutes, or render just a single car in ~seconds. This is such a huge time saver and has enabled me to iterate on car designs more quickly and easily than ever before. I’m already seeing the gains in much better sprites.&lt;/p&gt;

&lt;p&gt;Believe it or not this was the first Makefile I’ve ever needed to write from scratch. I knew enough about them to know that they would be a good fit for this task, and it was fun to learn more about something I only knew in passing.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 19 May 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/05/19/makefile/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/05/19/makefile/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Pre-rendering Ranger</title>
          <description>&lt;p&gt;Since very early on shadows in Daily Driver have just been simple rectangles: one size fits all, rendered from a single 3D model, and post-processed to add dithering. &lt;abbr title=&quot;Minimum Viable Product&quot;&gt;MVP&lt;/abbr&gt;, you know? Over time I decided to do multiple shadows, one each for short cars and long cars.&lt;/p&gt;

&lt;p&gt;Sometime later I threw caution to the wind and decided to render per-car shadows. However, the OpenSCAD &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;projection()&lt;/code&gt; command that I was using was so slow! In fact it zapped my desire to finish implementing the feature. Instead, I let it sit for many months.&lt;/p&gt;

&lt;p&gt;Recently, I picked things up again to get the a new trailer and demo out. And then it hit me, that if I flatten a car on the z-axis—as if Looney Tunes dropped a heavy weight on it—then that flat thing will be a close enough equivalent of a shadow for my use. So I did just that and the results were great, and more importantly very quick to render!&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-shadows-anim.gif&quot; alt=&quot;GIF&quot; title=&quot;Animation showing the theory of a model being squished down into its shadow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So I went all in and decided to not only render one shadow per-car but to render shadows for each individual frame. So now the direction of the front wheels and details of the body shape are reflected in the shadow. It might sound like a small thing but it really makes a big difference. You can see old vs new shadows in the image carousel below.&lt;/p&gt;

&lt;p&gt;It’s in situations like these that I’m really proud I put a ton of early effort into the tooling and build process that generates my sprites.&lt;/p&gt;

&lt;p&gt;Result!&lt;/p&gt;

&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;b&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-shadows-old.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-shadows-old.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-shadows-new.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-prerendered-shadows-new.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 82%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__staticimage,
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2) {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;.carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 18 May 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/05/18/prerendering-ranger/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/05/18/prerendering-ranger/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Happy New Year!</title>
          <description>&lt;p&gt;I hope you’re safe and well and wish you a great 2021. I’m back at it, and am confident this year will be the year of Daily Driver and more besides!&lt;/p&gt;

&lt;p&gt;Recent work on the game includes improvements to the physics of in-game objects and creation of yet more vehicles and levels.&lt;/p&gt;

&lt;p&gt;“The car’s the star”, as they say, so I have sunk untold hours into both the physics and graphics of many different cars to ensure that the depth of control and animation is enough to hold a players interest for the time I hope they will spend with my game. There’s no final vehicle line-up, as often some cars don’t look unique enough after the first rough model is tested in the game. But these two are keepers!&lt;/p&gt;

&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;b&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-happy-new-year-a.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-happy-new-year-a.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-happy-new-year-b.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-happy-new-year-b.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 82%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__staticimage,
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2) {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;.carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

&lt;p&gt;Interestingly, both these vehicles show off one aspect of the game that I’ve not really talked about so far: reference and nods to classic games. Here we can see an RC car (whose antenna wobbles!) that is a nod to games like Re-volt, RC Revenge, Smash Cars, RC de Go!, Excite Truck, RC Pro-Am etc. And the forklift is a nod to Shenmue and the infamous New Yokosuka Harbor District.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-happy-new-year.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 09 Jan 2021 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2021/01/09/happy-new-year/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2021/01/09/happy-new-year/</guid>
        </item>
      
    
      
        <item>
          <title>Band-kun バンドくん musician simulator (1990, KOEI)</title>
          <description>&lt;p&gt;I’ve been playing an old (1990, KOEI Co Ltd) Japanese NEC PC-9801 game バンドくん [Band-kun; Mr. Band; Band Man] where you start a band and have to recruit members, make some recordings and live a life of sex, drugs and rock’n’roll. It was also available for the Fujitsu FM Towns and Sharp X68000 Japanese personal computers.&lt;/p&gt;

&lt;h2 id=&quot;band-what&quot;&gt;Band-what?&lt;/h2&gt;

&lt;p&gt;Band-kun is a hybrid simulation/adventure/rhythm game. You explore a fictional city taking to various inhabitants, learning about the music and the music industry, recruiting band members and performing and recording music. You perform the music using mouse gestures, so it’s possible to ad-lib and receive better/worse results a little like playing a musical instrument. After recording you need mix the song in a studio, then get your friend Bob Marley to sell your CDs on the street corner, or figure out how to get the music played on the local radio station which is, of course, broadcasting from a zeppelin riding high above the city.&lt;/p&gt;

&lt;p&gt;You need to work dead-end jobs to pay your way, and repeat the recording/gigging process to work your way up through soul-destroying small club gigs to a big arena gig, and allegedly you can even die from the excess partying.&lt;/p&gt;

&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;b&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;c&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;d&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;e&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;f&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;g&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;g&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;f&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;g&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;f&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-01.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-01.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-02.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-02.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-03.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-03.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-04.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-04.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-05.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-05.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-06.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-06.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/band-kun-07.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-07.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;f&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;g&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 63%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__staticimage,
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}

.carousel__activator:nth-of-type(3):checked ~ .carousel__track {
  -webkit-transform: translateX(-200%);
          transform: translateX(-200%);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__slide:nth-of-type(3) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__controls:nth-of-type(3) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(3) {
  opacity: 1;
}

.carousel__activator:nth-of-type(4):checked ~ .carousel__track {
  -webkit-transform: translateX(-300%);
          transform: translateX(-300%);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__slide:nth-of-type(4) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__controls:nth-of-type(4) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(4) {
  opacity: 1;
}

.carousel__activator:nth-of-type(5):checked ~ .carousel__track {
  -webkit-transform: translateX(-400%);
          transform: translateX(-400%);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__slide:nth-of-type(5) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__controls:nth-of-type(5) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(5) {
  opacity: 1;
}

.carousel__activator:nth-of-type(6):checked ~ .carousel__track {
  -webkit-transform: translateX(-500%);
          transform: translateX(-500%);
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__slide:nth-of-type(6) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__controls:nth-of-type(6) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(6):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(6) {
  opacity: 1;
}

.carousel__activator:nth-of-type(7):checked ~ .carousel__track {
  -webkit-transform: translateX(-600%);
          transform: translateX(-600%);
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__slide:nth-of-type(7) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__controls:nth-of-type(7) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(7):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(7) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(3) {
  -webkit-transform: translateX(200%) translateZ(0);
          transform: translateX(200%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(4) {
  -webkit-transform: translateX(300%) translateZ(0);
          transform: translateX(300%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(5) {
  -webkit-transform: translateX(400%) translateZ(0);
          transform: translateX(400%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(6) {
  -webkit-transform: translateX(500%) translateZ(0);
          transform: translateX(500%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(7) {
  -webkit-transform: translateX(600%) translateZ(0);
          transform: translateX(600%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(3),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(3) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(4),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(4) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(5),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(5) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(6),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(6) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(7),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(7) {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;.carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

&lt;h2 id=&quot;playdate-version&quot;&gt;Playdate version?&lt;/h2&gt;

&lt;p&gt;It’s originally B&amp;amp;W so I figured it would look great on Playdate, so I made a little proof of concept.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-playdate.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Band-kun required a MIDI-capable sound card PLUS an external MIDI sound module - a very expensive 30,000JPY piece of equipment back in 1990. So it wasn’t a success and was forgotten about. But it eventually led to Guitaroo Man and the birth of the music game genre on PlayStation.&lt;/p&gt;

&lt;p&gt;Anyway! I’d love to licence Band-kun and re-release it on a modern device that can do the original concept justice. The Playdate crank and accelerometer could be used to perform the music!&lt;/p&gt;

&lt;p&gt;I wondered if anybody knows KOEI founder Youichi Erikawa (aka “Kou Shibusawa”)? Hook a brother up! バンドを組んでメンバーを集め、レコーディングをして、セックスとドラッグとロックンロールの生活を送るという昔（1990年、KOEI）のPC-9801のゲーム「バンドくん」をプレイしています。@koeitecmogames からライセンスしたいので、襟川 陽一 に協力をお願いします。&lt;/p&gt;

&lt;p&gt;Edit: since I originally wrote this twitter thread and blog post, contact has been made with KOEI’s licensing department. 🤞&lt;/p&gt;

&lt;h2 id=&quot;period-reviews&quot;&gt;Period reviews&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Detailed review from the 1991-01 issue of #マイコンBASIC micomBASIC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Courtesy of a &lt;a href=&quot;https://archive.org/details/micomBASIC_1991-01/page/n77/mode/2up&quot;&gt;scan at Internet Archive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-review-micomBASIC-1991-01.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Super Soft Hot Information: Band-kun #バンドくん in &lt;a href=&quot;https://twitter.com/hashtag/micomBASIC?src=hash&quot;&gt;#micomBASIC&lt;/a&gt;1990/12&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Courtesy of a &lt;a href=&quot;https://archive.org/details/micomBASIC_1990-12/page/n237/mode/2up&quot;&gt;scan at Internet Archive&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“SLG in which you form a band, gain experience through practice and live house performances, and aim to win a contest. After winning, the game turns into a highly flexible session software. MIDI compatible.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-review-micomBASIC-1990-12.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review of Band-kun #バンドくん in Technopolis #テクノポリス 1991/01&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Courtesy of a &lt;a href=&quot;https://archive.org/details/technopolis-1991-01/01_journal_1991-01/page/136/mode/2up&quot;&gt;scan at Internet Archive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;“We borrowed a studio and practiced hard with our friends to win the contest. Hone your skills!”&lt;/p&gt;

&lt;p&gt;“In the city, you’ll try to win a fight against a band member. It’s hard to get them to play with you at first.”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-review-technopolis-1991-01.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;translation-wip&quot;&gt;Translation (WIP)&lt;/h2&gt;

&lt;p&gt;I’ve been poking around in the Band-kun game files.&lt;/p&gt;

&lt;p&gt;Everything is stored uncompressed in very simple structures across a few files. I’ve not figured them all out, yet, but can see graphics (done), dialogue (partial), music (to-do). Band-kun ships with Scenario 1 “ZAP CITY 1991” and is able to play additional scenarios, but none were released.&lt;/p&gt;

&lt;p&gt;Regardless: it should be easy to create a translated version of the included scenario. And maybe even create a new scenario (varying difficulty depending on changes).&lt;/p&gt;

&lt;h2 id=&quot;user-manual&quot;&gt;User Manual&lt;/h2&gt;

&lt;p&gt;A scanned PDF for Band-kun #バンドくん is available with thanks to the Neo Kobe project &lt;a href=&quot;https://archive.org/details/band-kun-manual&quot;&gt;archive.org/details/band-kun-manual&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-cover.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;promotional-leaflet&quot;&gt;Promotional leaflet&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-leaflet-front.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-leaflet-back.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;download-the-game&quot;&gt;Download the game&lt;/h2&gt;

&lt;p&gt;Get the disk image at Internet Arcchive for &lt;a href=&quot;https://ia600100.us.archive.org/view_archive.php?archive=/22/items/NeoKobe-NecPc-98012017-11-17/Koei.zip&quot;&gt;PC-9801&lt;/a&gt; or FM-Towns&lt;/p&gt;

&lt;h2 id=&quot;all-the-faces&quot;&gt;All the faces&lt;/h2&gt;

&lt;p&gt;Here are all 120 “famous” faces, extracted from PC-9801 Band-kun, thanks to &lt;a href=&quot;https://twitter.com/fukui_keeekn/status/1223375503710539776&quot;&gt;@fukui_keeekn on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/band-kun-faces.png#pixel&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;birthday-blog-post&quot;&gt;Birthday blog post?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Check out my other &lt;a href=&quot;/tag/birthday/&quot;&gt;#birthday&lt;/a&gt; blog posts.&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 16 Dec 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/12/16/band-kun-musician-simulator-1990-koei/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/12/16/band-kun-musician-simulator-1990-koei/</guid>
        </item>
      
    
      
        <item>
          <title>デイリードライバー</title>
          <description>&lt;p&gt;The last couple of months have been tough going for a couple of reasons.&lt;/p&gt;

&lt;p&gt;Firstly, a new version of the Playdate SDK broke my game in a couple of important ways: my method of targeting 60fps stopped working, and more seriously the controls stopped working. The workaround for both of these issues was long and drawn out, but here’s a quick summary:&lt;/p&gt;

&lt;p&gt;Until this point I was waiting for the next frame update using the SDK &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; function: one line of code that waits for a required amount of time. A change in how this works meant I was stuck. My workaround was do it in a more naïve way - just constantly checking the system timestamp to see if the allowed time for the current frame has passed. Keep it simple, I guess.&lt;/p&gt;

&lt;p&gt;The overhead of idling the CPU—the time it takes for it to wind down, do the wait, and then wind back up—is actually quite substantial when it takes a few milliseconds and you only have sixteen of them for each update!&lt;/p&gt;

&lt;p&gt;The end result is that the game is now running… better than ever. Even after these issues were resolved at a higher level by the Playdate SDK team, I have kept using my workarounds as the game runs faster. So, silver linings and all that!&lt;/p&gt;

&lt;p&gt;Secondly, an important issue that remains unresolved is exactly how—and when—Daily Driver will be released. I’m hopeful that will be as part of a Playdate Season, where games are delivered to the device on a schedule and you don’t know what game you’ll be playing until you see the light flash and you pick up and wake up your device. That’s the magic I want my players to have a piece of. That might turn out to be later rather than sooner, so we’ll have to be patient.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-katakana.png#playdate&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Anyway, other news: I’ve been trying to decide how to render the name of the game in Japanese. The English title uses &lt;em&gt;&lt;strong&gt;Futura Bold Oblique&lt;/strong&gt;&lt;/em&gt; which is a style that does not translate directly into non-Roman typefaces. I had found some bold Japanese fonts, with a little bit of character, but they seemed too cute and not geometric enough. After much investigation and many mockups I opted to draw the necessary katakana characters by hand, on a grid, and it’s turned out rather well. I’d love to expand this into a full typeface, but that’s a project for another time.&lt;/p&gt;

&lt;p&gt;Doing this sort of graphics work, or car design/rendering, are my goto procrastination tasks when I don’t have enough mojo to dive into the code and tackle the remaining work. So I’m sort of treading water on the final push of work needed to get the game over the line.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 14 Dec 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/12/14/daily-driver/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/12/14/daily-driver/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Automation Improvements</title>
          <description>&lt;p&gt;The recent automation was really just help with organisation. As soon as I started looking at running OpenSCAD from the shell/command-line it became obvious that I could do the rendering and organisation in one step without having to use external apps like Hazel.&lt;/p&gt;

&lt;p&gt;So, that’s now done. I render all the frames, with more sensible filenames, to a single folder.&lt;/p&gt;

&lt;p&gt;If I run all the renders one after the other, maxing out a single CPU core (99% CPU usage), time taken:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~17 seconds 🐢&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But, using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt; directive and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait&lt;/code&gt; command, I can run the renders in parallel (well, technically it’s one process each; and batches of 32 works best) using all 6 CPU cores (~485% CPU usage), time taken:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~10 seconds 🐇&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;…the beauty of the command line!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note to self: don’t publish a post about an automation breakthrough until the dust has settled.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 09 Oct 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/10/09/automation-improvements/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/10/09/automation-improvements/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Automation</title>
          <description>&lt;p&gt;In preparation for regenerating my many cars with x3 the number of sprites, I thought I’d try to sort the rendered frames automatically into named folders because this is fiddly manual work I really don’t enjoy, and a bit of a bottleneck in my asset generation. For each pose I have to render the frames then group the new image files into a folder that describes that pose, as these multiple folders are later be used for batch processing.&lt;/p&gt;

&lt;p&gt;I could use macOS Folder Actions for this, but I’ve been using an app called &lt;a href=&quot;https://www.noodlesoft.com/&quot;&gt;Hazel&lt;/a&gt; for many years to do this sort of thing, so that was my first choice.&lt;/p&gt;

&lt;p&gt;The hard work is done with a shell script, as I’m quite comfortable writing those.&lt;/p&gt;

&lt;h2 id=&quot;flow&quot;&gt;Flow&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;get most recently saved .scad file&lt;/li&gt;
  &lt;li&gt;parse filename to capture car name&lt;/li&gt;
  &lt;li&gt;parse file contents for left/right/forward/backward tilt values&lt;/li&gt;
  &lt;li&gt;concatenate all this information as our new folder name&lt;/li&gt;
  &lt;li&gt;create new folder&lt;/li&gt;
  &lt;li&gt;move matching file into new folder&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means that the folder name will change based on the render settings in the file—perfect!&lt;/p&gt;

&lt;p&gt;I still have to make 9 small sets of manual text changes to render each car pose, so that’s the next thing I’ll try to automate by running OpenSCAD from the command line.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-automation.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 07 Oct 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/10/07/automation/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/10/07/automation/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Weight Transfer</title>
          <description>&lt;p&gt;I’ve been playing old Japanese PlayStation game &lt;a href=&quot;https://digitaldriftracer.wordpress.com/2019/06/09/touge-max-series-overview/&quot;&gt;Touge Max G&lt;/a&gt; and besides this having a gymkhana mode similar to aspects of Daily Driver, it also has a realistic handling model. One of the things that struck me about that was how the car rocks back and forth when accelerating and braking/reversing. One of the other games in the Touge series also has a school mode that talks you through this concept of weight transfer. It’s realistic and adds some level of dynamics to the car, making it feel less like a solid block sliding around.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-weight-transfer.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So I’ve added this effect to Daily Driver and will be refining it going forward. I find it breathes extra life into the car just as it does in other games with full 3D physics modelling. It requires 3x the number of car sprites but because I render them from 3D it’s not much extra work and I think it’s well worth the effort.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-weight-transfer.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 03 Oct 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/10/03/weight-transfer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/10/03/weight-transfer/</guid>
        </item>
      
    
      
        <item>
          <title>Found whilst backing up an old PC</title>
          <description>&lt;p&gt;Backed up a very old laptop and found a bunch of cool old stuff from 15-20 years ago! &lt;a href=&quot;https://twitter.com/hashtag/thread?src=hash&quot;&gt;#thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2003-04-25: Custom Fruit Labels for a Zelda: Wind Waker competition (I think in Official Nintendo Magazine?) I sent them a fake plastic pear with one of these these stuck on.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaSuHAXkAAV91O.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2005-01-18: grid-based music puzzle game called BEAT HIT&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaTe86WAAAnz7d.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2004-12-24: game mockup “Katamari Christmasy” 2D side-scroller&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaUBBPWkAAiM7-.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2004-07-11: reverse engineering “Mini Golf” JAVA cell phone game to make custom levels. w/ hyphz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaUjB5WkAYp9k7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2004-03-10: Atari arcade game Super Sprint themed T-shirt&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaVQKVXYAA5fP-.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2004-07-22: source code (Blitz Basic, Windows PC) for my game Wire Hang Redux, which you can still grab and play for free at &lt;a href=&quot;https://gingerbeardman.itch.io/wire-hang-redux&quot;&gt;(gingerbeardman.itch.io/wire-hang-redux)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaWOLWXkAEjkAo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2004-12-21: various themes for Sony Ericsson K700i cell phone&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaWoAnWsAEbbFn.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-01-15: source code for my Futurama-themed Robotron clone “Bendertron”&lt;/p&gt;

&lt;p&gt;2001-04-24: WIP Mode 7 style kart game “Manga Kart”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaZPz9WsAEnBIT.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-03-04: source code for Pang style bouncing ball physics&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaZaRrXcAAZ-Zz.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2003-07-02: beach-themed QIX clone “QUARTZ”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaaT7tXcAAOD-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2003-07-02: source code for rainbow block matching puzzler “ROY” - it’s not balanced, or much fun, but it’s still downloadable at &lt;a href=&quot;http://www.gingerbeardman.com/archive/roy/&quot;&gt;(gingerbeardman.com/archive/roy/)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjabK4dXcAETDJN.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2000-2003: source code for my Sensible Soccer clone “Simple Soccer” &lt;a href=&quot;http://www.gingerbeardman.com/archive/soccer/&quot;&gt;(gingerbeardman.com/archive/soccer/)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjabtL9WoAMi2G6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-09-17: source code for aborted attempt at bringing &lt;a href=&quot;https://twitter.com/armyoftrolls&quot;&gt;@armyoftrolls&lt;/a&gt; mockup “Space Squad 5” to life&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjacK5YX0AQ2UfE.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-08-23: source code for my entry into the BlitzCoder Stupidest Game competition, Summer 2002. “Terra Firma” still available to download and play at &lt;a href=&quot;http://www.gingerbeardman.com/archive/terrafirma/&quot;&gt;(gingerbeardman.com/archive/terraf…)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/Ejac_qtXYAEWnIG.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-08-24: source code for my kayaking simulator “yaking”&lt;/p&gt;

&lt;p&gt;hurrah! was hoping i’d find this. will rinstate working download ASAP at &lt;a href=&quot;http://www.gingerbeardman.com/archive/yaking/&quot;&gt;(gingerbeardman.com/archive/yaking/)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/Ejadk2tWsAIM8Rg.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2000-06-10: photos from my first digital camera (a Fujifilm FinePix 1400 Zoom) including some of my first car (a 1972 FIAT 500)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjafAs2XYAAMpze.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;1995-1998: my University Comp Sci directory photos (I was age 18-21)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjagkQgXYAA1Slr.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2002-05-23: original artwork for my Sensible Soccer T-shirt that was sold in River Island stores across the UK (still a shame they didn’t print the lines on the neck and shoulders!)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjahgN2XsAE9eVU.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2000-08-06: email attachment ATT09176.jpeg a photo of forest fire. (Bitterroot National Forest, Montana, on Aug. 6, 2000) &lt;a href=&quot;https://earthobservatory.nasa.gov/images/843/bitterroot-inferno&quot;&gt;(earthobservatory.nasa.gov/images/843/bit…)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjaieMTX0AIMt5x.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…plus tons of work files, game screenshots and ROMs, failed prototypes, and random stuff I found interesting. Which goes to show that half a lifetime ago I was exactly the same person I am today. Phew. &lt;a href=&quot;https://twitter.com/hashtag/end?src=hash&quot;&gt;#end&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, a couple more…&lt;/p&gt;

&lt;p&gt;2003-06-29: me taking photos of a big old widescreen CRT showing the Samsung N504 Virtual Light Machine (VLM-2) - still got it the NUON - no it’s not for sale ;)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/Ejam_NMXkAAJ5Cu.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2005-09-05: my favourite game at the time was a Japanese skill game called “Pendulumania” (version 1.3 A) still downloadable from &lt;a href=&quot;https://www.vector.co.jp/magazine/softnews/000126/n0001261.html&quot;&gt;(vector.co.jp/magazine/softn…)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/Ejap3gFWsAICWEJ.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2000-10-16: the original Fontographer .fog .fon .ttf files for my font BLOCKOUT (inspired by The Designers Republic but - contrary to their threatening legal letter - actually designed on a completely different grid system!) &lt;a href=&quot;https://www.flickr.com/photos/emsef/5706680402/&quot;&gt;(flickr.com/photos/emsef/5…)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/EjarqSNWoAICnYG.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 03 Oct 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/10/03/found-whilst-backing-up-an-old-pc/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/10/03/found-whilst-backing-up-an-old-pc/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Social Update</title>
          <description>&lt;p&gt;The launch of this Patreon for Daily Driver also sees the game’s &lt;a href=&quot;https://forums.tigsource.com/index.php?topic=70808.msg1428724#msg1428724&quot;&gt;topic on TIGSource Forums&lt;/a&gt; as the first Playdate game!&lt;/p&gt;

&lt;p&gt;And also &lt;a href=&quot;https://www.indiedb.com/games/daily-driver&quot;&gt;on IndieDB&lt;/a&gt; as perhaps the first Playdate game? Though I do see fellow devs and Patreon Creators &lt;a href=&quot;https://www.patreon.com/rngparty&quot;&gt;RNG Party&lt;/a&gt; are already listed but they are yet to add their current Playdate game.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 05 Sep 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/09/05/social-update/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/09/05/social-update/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Cannonball Run</title>
          <description>&lt;p&gt;Accidental new game mode discovered?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“Cannonball Run”&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Collect stuff whilst a barrage of heavy things bounce around the screen!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was a result of my continued work implementing different surface frictions, and I mistakenly set the cones to not be affected by friction and thus never slow down. Hitting them a few times was enough to get them moving at a good speed, and then I drove around the screen.&lt;/p&gt;

&lt;p&gt;What I didn’t appreciate is that my collision model uses elastic collision, which allows the car to knock stuff over in a quite pleasing way where the car takes a little bit of a knock. But if those things are moving fast enough, as the cones are here, then any collision will also affect the car to a larger degree. You can see the car being pushed around by the out of control traffic cones.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-one-cannonball-run.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 31 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/31/cannonball-run/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/31/cannonball-run/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: One Shade of Grey?</title>
          <description>&lt;p&gt;Since I am targeting 60fps one of the things I can do is flash a black sprite every other frame to get a shade of grey. Yes! Grey on a black and white screen.&lt;/p&gt;

&lt;p&gt;It only works at high frame rates (note: 50fps isn’t high enough!) because the screen is &lt;em&gt;so damned good&lt;/em&gt; that flashing at a slower rate simply looks like… an image flashing. The effects is also visible on device for the same reason.&lt;/p&gt;

&lt;p&gt;So I’m not sure I’ll use it, as all other shadows are dithered and flashing them all will hit the frame rate. But it was fun to try! One for another game, perhaps?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I believe this technique was used on other systems with limited colours, such as Game Boy and Palm (to get 4 shades), certain Commodore 64 games (eg. Creatures 2) did it to get never-before-seen colours, and of course old arcade and video games often did exactly my trick to get their semi-opaque shadows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-one-shade-grey.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 19 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/19/one-shade-of-grey/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/19/one-shade-of-grey/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Eight-Six</title>
          <description>&lt;p&gt;When you get a crazy idea that you’ll probably never be able to use, but you do it anyway, just to scratch the itch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-eight-six.jpg&quot; alt=&quot;JPG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-eight-six.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 18 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/18/eight-six/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/18/eight-six/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Playable Demo</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-playable-demo.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A made a demo build of Daily Driver. It is based on code a couple weeks old (dated &lt;strong&gt;30 July 2020&lt;/strong&gt;) so whilst not representative of where I am right now with the game it does show my progress since the last build I shared at the start of June.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;any combination of d-pad, A/B, Crank&lt;/li&gt;
  &lt;li&gt;d-pad U/D, or A/B = accelerate/brake&lt;/li&gt;
  &lt;li&gt;d-pad L/R, or Crank = steer left/right&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
  &lt;li&gt;runs at 60fps on device (50fps in Simulator)&lt;/li&gt;
  &lt;li&gt;pressing Menu twice will reset the current stage layout&lt;/li&gt;
  &lt;li&gt;pressing Menu then Options will load the next stage&lt;/li&gt;
  &lt;li&gt;19 different stages (all cone layouts in this build)&lt;/li&gt;
  &lt;li&gt;includes level editor!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Debug Keys for game (simulator only):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;E = open level editor&lt;/li&gt;
  &lt;li&gt;F = toggle fps indicator&lt;/li&gt;
  &lt;li&gt;J = jump!&lt;/li&gt;
  &lt;li&gt;L = list all sprites&lt;/li&gt;
  &lt;li&gt;N = next stage&lt;/li&gt;
  &lt;li&gt;P = play replay data&lt;/li&gt;
  &lt;li&gt;R = print replay data to console&lt;/li&gt;
  &lt;li&gt;T = toggle telemetry&lt;/li&gt;
  &lt;li&gt;U = toggle frame limiter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controls for editor (simulator only):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;d-pad = move cursor&lt;/li&gt;
  &lt;li&gt;A = place an object or increment object under the cursor&lt;/li&gt;
  &lt;li&gt;B = toggle precision mode
    &lt;ul&gt;
      &lt;li&gt;cursor moves in smaller increments (5px vs 20px)&lt;/li&gt;
      &lt;li&gt;drag/move item under cursor&lt;/li&gt;
      &lt;li&gt;A = delete item under cursor&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Debug Keys for editor (simulator only):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;B = new blank stage&lt;/li&gt;
  &lt;li&gt;D = dump stage JSON to console (for copy and pasting)&lt;/li&gt;
  &lt;li&gt;E = exit level editor&lt;/li&gt;
  &lt;li&gt;O = output stage as “m-edited.json” in game Sandbox directory&lt;/li&gt;
  &lt;li&gt;Z = undo (deletes last item placed)&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 15 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/15/playable-demo/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/15/playable-demo/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Post-processing workflow</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-post-processing.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;My post-processing to 1-bit is fairly simple. I use a bespoke tool that allows me to have “live” (realtime) manual control over a bunch of image filters so I can see the results immediately.&lt;/p&gt;

&lt;p&gt;But essentially it’s:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;convert to greyscale, using one of many algorithms&lt;/li&gt;
  &lt;li&gt;reduce colours to 1-bit, decide on dithering or threshold level on case-by-case basis&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The grey shades that I applied to my model in OpenSCAD give an element of control during this conversion process. Greys can be pushed either way, towards black or white, depending on my need with the specific model I am working on.&lt;/p&gt;

&lt;p&gt;In this instance I desaturated the greys which blows them out to nearer white. And then I chose to threshold to reduce to b/w.&lt;/p&gt;

&lt;p&gt;I also have the wheels as a separate finished image so I don’t have to worry if their detail is lost during this phase, I can just paste over the accurate/finished wheels.&lt;/p&gt;

&lt;p&gt;Final result, unedited:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-post-processing.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I would later touch up the sprite by hand to reinforce any details I think have been lost. I use Piskel for edited sprites because it has really nice sprite sheet support, drag and drop loading, and quick and versatile exporting.&lt;/p&gt;

&lt;p&gt;Aside: 32 is a number that is a leftover from a different prototype and it’s stuck. I guess it should really be 36? or 24? or 18?. But it’s too late now! Actually it would be relatively easy to change but I have bigger fish to fry.&lt;/p&gt;

&lt;p&gt;The animations alone could run at 99fps—it’s anything that causes more drawing which slow things down. Collisions, not because they are computationally heavy, but because they cause a lot of sprite updates - which means drawing moving things - to happen. I’m working hard to maintain 60fps on device (50fps in simulator for… reasons) and am excited I’ve managed to get here.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 10 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/10/post-processing-workflow/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/10/post-processing-workflow/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Retrobatch workflow</title>
          <description>
&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;b&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;c&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;d&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-1.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-1.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-2.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-2.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-3.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-3.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-4.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-retrobatch-workflow-4.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 82%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__staticimage,
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}

.carousel__activator:nth-of-type(3):checked ~ .carousel__track {
  -webkit-transform: translateX(-200%);
          transform: translateX(-200%);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__slide:nth-of-type(3) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__controls:nth-of-type(3) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(3) {
  opacity: 1;
}

.carousel__activator:nth-of-type(4):checked ~ .carousel__track {
  -webkit-transform: translateX(-300%);
          transform: translateX(-300%);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__slide:nth-of-type(4) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__controls:nth-of-type(4) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(4) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(3) {
  -webkit-transform: translateX(200%) translateZ(0);
          transform: translateX(200%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(4) {
  -webkit-transform: translateX(300%) translateZ(0);
          transform: translateX(300%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(3),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(3) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(4),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(4) {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;.carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

&lt;h2 id=&quot;retrobatch&quot;&gt;Retrobatch&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;process dumped frames x 32
    &lt;ul&gt;
      &lt;li&gt;once each for left, right and straight directions&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;stitch processed frames together as sprite-sheets x 3
    &lt;ul&gt;
      &lt;li&gt;we end up with three long images&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;stitch 3x sprite-sheets together
    &lt;ul&gt;
      &lt;li&gt;we end up with our final image ready for post-processing&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Edit, August 2020: since writing this post I’ve been able to condense this process into 1 single workflow that executes much faster. See image 4. Thanks to Gus, maker of Retrobatch!&lt;/p&gt;

&lt;p&gt;Edit, June 2021: I replaced my all uses of Retrobatch with imagemagick commands.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 09 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/09/retrobatch-workflow/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/09/retrobatch-workflow/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: OpenSCAD workflow</title>
          <description>
&lt;div class=&quot;carousel__holder&quot;&gt;
    &lt;div class=&quot;carousel&quot;&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;a&quot; checked=&quot;checked&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;b&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;c&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;d&quot; /&gt;
        
          &lt;input class=&quot;carousel__activator&quot; type=&quot;radio&quot; name=&quot;carousel&quot; id=&quot;e&quot; /&gt;
        
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
          
          
          
          
          &lt;div class=&quot;carousel__controls&quot;&gt;
              &lt;label class=&quot;carousel__control carousel__control--backward&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
              &lt;label class=&quot;carousel__control carousel__control--forward&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
          &lt;/div&gt;
        
        &lt;div class=&quot;carousel__track&quot;&gt;
          &lt;ul&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-1.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-1.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-2.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-2.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-3.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-3.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-4.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-4.png&quot; /&gt;&lt;/li&gt;
            
            &lt;li class=&quot;carousel__slide&quot; style=&quot;background-image: url(&apos;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-5.png&apos;);&quot;&gt;&lt;img class=&quot;carousel__staticimage&quot; src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-openscad-workflow-5.png&quot; /&gt;&lt;/li&gt;
            
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class=&quot;carousel__indicators&quot;&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;a&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;b&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;c&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;d&quot;&gt;&lt;/label&gt;
            
              &lt;label class=&quot;carousel__indicator&quot; for=&quot;e&quot;&gt;&lt;/label&gt;
            
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.carousel__holder {width: 100%; position: relative; padding-bottom: 82%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__staticimage,
.carousel__controls,
.carousel__activator {
  display: none;
}

.carousel__activator:nth-of-type(1):checked ~ .carousel__track {
  -webkit-transform: translateX(-000%);
          transform: translateX(-000%);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__slide:nth-of-type(1) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__controls:nth-of-type(1) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(1):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(1) {
  opacity: 1;
}

.carousel__activator:nth-of-type(2):checked ~ .carousel__track {
  -webkit-transform: translateX(-100%);
          transform: translateX(-100%);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__slide:nth-of-type(2) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__controls:nth-of-type(2) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(2):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(2) {
  opacity: 1;
}

.carousel__activator:nth-of-type(3):checked ~ .carousel__track {
  -webkit-transform: translateX(-200%);
          transform: translateX(-200%);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__slide:nth-of-type(3) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__controls:nth-of-type(3) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(3):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(3) {
  opacity: 1;
}

.carousel__activator:nth-of-type(4):checked ~ .carousel__track {
  -webkit-transform: translateX(-300%);
          transform: translateX(-300%);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__slide:nth-of-type(4) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__controls:nth-of-type(4) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(4):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(4) {
  opacity: 1;
}

.carousel__activator:nth-of-type(5):checked ~ .carousel__track {
  -webkit-transform: translateX(-400%);
          transform: translateX(-400%);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__slide:nth-of-type(5) {
  transition: opacity 0.5s, -webkit-transform 0.5s;
  transition: opacity 0.5s, transform 0.5s;
  transition: opacity 0.5s, transform 0.5s, -webkit-transform 0.5s;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  -webkit-transform: scale(1);
          transform: scale(1);
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__controls:nth-of-type(5) {
  display: block;
  opacity: 1;
}
.carousel__activator:nth-of-type(5):checked ~ .carousel__indicators .carousel__indicator:nth-of-type(5) {
  opacity: 1;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
  color: #fafafa;
  mix-blend-mode: difference;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 10px;
  width: 10px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}

.carousel__track .carousel__slide:nth-of-type(1) {
  -webkit-transform: translateX(000%) translateZ(0);
          transform: translateX(000%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(2) {
  -webkit-transform: translateX(100%) translateZ(0);
          transform: translateX(100%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(3) {
  -webkit-transform: translateX(200%) translateZ(0);
          transform: translateX(200%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(4) {
  -webkit-transform: translateX(300%) translateZ(0);
          transform: translateX(300%) translateZ(0);
}

.carousel__track .carousel__slide:nth-of-type(5) {
  -webkit-transform: translateX(400%) translateZ(0);
          transform: translateX(400%) translateZ(0);
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

.carousel__slide:nth-of-type(1),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(1) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(2),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(2) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(3),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(3) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(4),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(4) {
  background-size: cover;
  background-position: center;
}

.carousel__slide:nth-of-type(5),
.carousel--thumb .carousel__indicators .carousel__indicator:nth-of-type(5) {
  background-size: cover;
  background-position: center;
}

&lt;/style&gt;

&lt;script&gt;
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === &apos;none&apos;) {
                return false;
            } else if ($style.visibility === &apos;hidden&apos;) {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === &apos;block&apos; || $style.display === &apos;inline-block&apos;) &amp;&amp;
                $style.height === &apos;0px&apos; &amp;&amp; $style.overflow === &apos;hidden&apos;) {
                return false;
            } else {
                return $style.position === &apos;fixed&apos; || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll(&apos;.carousel__control--forward&apos;);
    for(i=(elements.length - 1);i&gt;-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
&lt;/script&gt;

&lt;p&gt;I took the plunge and upgraded to a Mac mini and 4K display so had to migrate my setup and then figure out why my workflow was broken (spoiler: retina!) compared to my old rMBP with non-retina display.&lt;/p&gt;

&lt;p&gt;So, my workflow uses the following apps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://openscad.org&quot;&gt;OpenSCAD&lt;/a&gt; “The Programmers Solid 3D CAD Modeller”&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://flyingmeat.com/retrobatch/&quot;&gt;Retrobatch&lt;/a&gt; “a unique application for automating actions on multiple images at the same time”&lt;/li&gt;
  &lt;li&gt;post-processing “greyscale and dithering tool” (I use my own realtime tool, but any image editor would do it to a degree, see this other thread)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is so I can re-run a workflow at any point (maybe in a make file) which I often do during development. These become executable assets, of sorts, in my project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenSCAD&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;define 3D models (I get a feeling like coding CSS in a strange way)&lt;/li&gt;
  &lt;li&gt;animate the model spinning through one 360-degree rotation&lt;/li&gt;
  &lt;li&gt;dump frames out as PNG files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the model definition to try out:&lt;/p&gt;

&lt;noscript&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/gingerbeardman/a0a0b967c480ab973d40aaf5e78fd47f&quot;&gt;View the source code as a Gist&lt;/a&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/gingerbeardman/a0a0b967c480ab973d40aaf5e78fd47f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I love building 3D this way, it’s kind of like LEGO. I use basic geometric building blocks (cube, sphere, cylinder, polygon, etc) and some boolean operations (difference, intersection, union). There are some other cool things (hull, minkowski). I have the commands in &lt;a href=&quot;https://dash.app/&quot;&gt;Dash.app&lt;/a&gt;alongside the Playdate SDK docs.&lt;/p&gt;

&lt;p&gt;In the image 2 you can see what the model looks like with all the blocks I have used to make it visible at once.&lt;/p&gt;

&lt;p&gt;My particular approach is &lt;em&gt;subtractive&lt;/em&gt;— kind of like sculpting—I start with large blocks and cut away at them using other shapes and the &lt;em&gt;difference&lt;/em&gt; function. When finding the exact placement for a block I use the &lt;em&gt;#&lt;/em&gt; precedent which makes the blocks show up as semi-opaque red blocks. See main image.&lt;/p&gt;

&lt;p&gt;I colour each block in a one or two shades of grey, black and white. This is to help with the conversion to 1-bit later on. It’s not so obvious here as the lighting makes the colours look many different shades - for example the wheels are black with white centre but look grey here. See image 3.&lt;/p&gt;

&lt;p&gt;Using some simple programming constructs and variables I can add booleans to trigger different states, I use this for angled front wheels and tilted car body. See image 4.&lt;/p&gt;

&lt;p&gt;And also to set the distance and rotation of the camera relative to the model when in animation mode. In this mode I enter a speed (doesn’t matter but higher the better) number of frames = 32, and the tick the box to dump the images. The tick disappears when the images are all done. See image 5.&lt;/p&gt;

&lt;p&gt;I also rendered the skid marks, car shadow, and some other elements.&lt;/p&gt;

&lt;p&gt;There is a lot that is annoying about this app&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;not retina-optimised (so I run it in Low Resolution, set using Get Info on the app)&lt;/li&gt;
  &lt;li&gt;runs maxed out on a single core&lt;/li&gt;
  &lt;li&gt;doesn’t have configurable lighting (I’d prefer uniform or no lighting)&lt;/li&gt;
  &lt;li&gt;Qt Framework app, so not really macOS-native&lt;/li&gt;
  &lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…but I still use it! I am not aware of anything else quite like it.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 08 Aug 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/08/08/openscad-workflow/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/08/08/openscad-workflow/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Shine Get!</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-shine-get.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Added steering assist, which locks your final steering direction to one of 16 directions, rather than allowing any angle. This prevents over steer when trying to turn to the specific directions required in a level. Of course this is optional; it is variable and can be switched off if the player does not want it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;25 July 2020.&lt;/strong&gt; I added another type of object, one that disappears upon collision meaning that it is collectable. It’s a kind of coin with a coin-collecting sound effect.&lt;/p&gt;

&lt;p&gt;No changes to physics have been made in a long time, but I guess on this level there are no collisions so the car is mostly at full throttle and so seems a bit more responsive than previously?&lt;/p&gt;

&lt;p&gt;I’ve already done multiple car types with different handling and sprites. Still more to do though.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 21 Jul 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/07/21/shine-get/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/07/21/shine-get/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Instant Replay</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-instant-replay.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I guess this looks like a looped GIF, but it’s not!&lt;/p&gt;

&lt;p&gt;I added some quite simple code to record every button press and the tick time at which it happened. The beauty of this approach is that most frames there are no button presses so the recorded data is very small. The work I’ve previously put in structuring the game in an Object-Oriented way really paid off.&lt;/p&gt;

&lt;p&gt;The game engine is completely deterministic—it has no random elements—so playing back the data is also very simple and the result is an exact frame by frame replay.&lt;/p&gt;

&lt;p&gt;Seeing this for the first time felt like magic. This is why I love developing games!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 17 Jul 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/07/17/instant-replay/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/07/17/instant-replay/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: High Frame Rates are Best Frame Rates</title>
          <description>&lt;p&gt;Over the course of development I’d been unhappy with the game running at 30fps, as it did not feel responsive enough. I’m a big believer that if a gamer features fast action gameplay and requires quick reactions then higher frame rates and lower response time are what is needed.&lt;/p&gt;

&lt;p&gt;Over the lifetime of the project I had beeb experimenting with running the game at a higher frame rate, as the maximum frame rate supported by Playdate SDK is 50fps. When I wrote my physics I did so in a way that it was not tied to one specific frame rate. Actually, it’s more correct to say that it is tied to the highest frame rate of 50fps but is done so in a way that it can be adapted to any frame rate.&lt;/p&gt;

&lt;p&gt;Anyway, after a round of optimisations and general improvements to the way I did both the skid marks (draw direct to background image rather as sprites) and sound effects (not attaching the whole sound engine to each object!) my game was running at max frame rate.&lt;/p&gt;

&lt;p&gt;So, I decided to see how high the game would run if I removed the frame limiter (which the SDK allows) and to my surprise my hame was running between 60 and 75fps. At this point I had the crazy idea of running my game at 60fps, because… why not? I wrote my own simple frame limiter (which would be more precise if the SDK allowed finer grained time reporting) and now the game runs faster and smoother than games should on Playdate.&lt;/p&gt;

&lt;p&gt;One interesting thing I noticed was that if I used my frame limiter code to limit the game to 50fps, I actually had a bunch more time, ~3ms, to do stuff per frame update than if I used the SDK frame limiter! I can only assume that every frame update the SDK frame limiter is doing something I am not doing.&lt;/p&gt;

&lt;p&gt;So, writing my own frame limiter clawed back some time from the SDK and also allowed me to go harder, better, faster, stronger. Double win!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Tue, 14 Jul 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/07/14/high-frame-rates/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/07/14/high-frame-rates/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Showreel</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-showreel.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Trying out some different things: a grab bag of scenarios.&lt;/p&gt;

&lt;p&gt;This long GIF shows several scenarios, different physics, and more! Essential viewing.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 04 Jul 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/07/04/showreel/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/07/04/showreel/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Chequered Flag</title>
          <description>&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-chequered-flag.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bit of fun at lunch today.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 24 Jun 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/06/24/chequered-flag/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/06/24/chequered-flag/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Influences</title>
          <description>&lt;p&gt;Some fellow Playdate developers commented that at this point the game reminded them of &lt;em&gt;Ivan “Ironman” Stewart’s Super Off Road&lt;/em&gt;, &lt;em&gt;Super Sprint&lt;/em&gt; and even &lt;em&gt;Rocket League&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A few of my influences for vibe:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Atari’s &lt;em&gt;Sprint&lt;/em&gt; series, including &lt;em&gt;Badlands&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Ivan “Ironman” Stewart’s Super Off Road&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Wild Wheels&lt;/em&gt; (a &lt;a href=&quot;https://www.mobygames.com/game-group/ball-sports-with-vehicles&quot;&gt;car soccer game&lt;/a&gt; that pre-dates &lt;em&gt;Rocket League&lt;/em&gt; by ~20 years)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for gameplay:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;ExciteBots: Trick Racing&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Mario Kart DS/Wii&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Power Drive&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Richard Burns Rally&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;The Italian Job: LA Heist&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Pro Rally&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Runabout&lt;/em&gt; series&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;GTi Club&lt;/em&gt; series&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;1080°&lt;/em&gt; series&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…so many more, some of which are not even driving games!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/06/18/influences/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/06/18/influences/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Off Road</title>
          <description>&lt;p&gt;&lt;strong&gt;6 June 2020.&lt;/strong&gt; Finally found and fixed a bug in my collision code - needed to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;math.abs()&lt;/code&gt; in one place to avoid some double negatives messing up collision rebound direction. D’oh!&lt;/p&gt;

&lt;p&gt;And now it’s time to Play Ball! I added a lap timer and a cool little LCD font.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-off-road.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9 June 2020.&lt;/strong&gt; The core flow of the game has been decided: there will be daily driving challenges with online leaderboards. So the game has found a name: Daily Driver.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12 June 2020.&lt;/strong&gt; Video of gameplay footage and sound effects: &lt;a href=&quot;https://www.youtube.com/watch?v=I57JxBp4kBM&quot;&gt;www.youtube.com/watch?v=I57JxBp4kBM&lt;/a&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 06 Jun 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/06/06/off-road/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/06/06/off-road/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Gameplay</title>
          <description>&lt;p&gt;I have redone the collision/rebound physics, and car visual and steering is now affected when colliding - makes collisions feel really physical. Tyres and Cone obstacles have different collision properties so they feel different when you hit them. It’s a lot of fun to simply drive around and knock into things, which makes me confident I’m onto something good here.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-gameplay.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 June 2020.&lt;/strong&gt; I’m now happy enough with the handling, time to get some gameplay in here. At this point the game is running at the Playdate SDK default of 30fps.&lt;/p&gt;

&lt;p&gt;First playable demo released to Playdate Developer Preview group!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Fastest Time Challenge”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;hit all 8 cones as quickly as possible&lt;/li&gt;
  &lt;li&gt;obstacles getting stuck under your car will slow you down!&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 31 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/31/gameplay/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/31/gameplay/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Obstacles</title>
          <description>&lt;p&gt;At this point I have three rows of rotated cars in the sprite sheet: each has wheels pointing in different directions.&lt;/p&gt;

&lt;p&gt;I’m currently doing the skid marks as sprites (which is why they disappear over time) partly because it was easy to get going, and partly to try to figure out some performance limits (~350 sprites in the GIF below, 25 of which are collidable and have my custom physics applied). Will be drawing skids marks straight to screen at some point in the future.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-obstacles.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Short term goal is to have some lap races/time-trials, plus a “driving test” or “stunt driving” mode which is what you’re seeing here.&lt;/p&gt;

&lt;p&gt;Codename is currently: Crank Turismo&lt;/p&gt;

&lt;p&gt;At this point you can’t hear my great synth-powered car engine and skidding sfx!&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 30 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/30/obstacles/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/30/obstacles/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: from 3D to 2D</title>
          <description>&lt;p&gt;At this point, the only thing that remained of the prototype was the car sprite so I wondered about creating a new one myself. It uses 32 different images of the car with different rotations, making for smooth animation and movement on screen.&lt;/p&gt;

&lt;p&gt;Whilst I could draw all those frames by hand, I decided to go down a path that could produce assets on demand. That way if I change my mind I can reprocess the assets whenever I feel like it. The initial process was easy to setup, but I’ve been taking and simplifying the automation process ever since.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-from-3d-to-2d-a.png&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’d previously used OpenSCAD to create 3D models, so it was a natural and easy choice. Also, it’s the only 3D app I’ve ever used—not even Blender! Models are created using a definition language (think of it as a bit like CSS) where you can define shapes and how they interact. I also use the animation function to set the viewpoint and rotate the car whilst automatically saving the images.&lt;/p&gt;

&lt;p&gt;In OpenSCAD I lock the view angle and zoom. I tie rotation to the animation value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$t&lt;/code&gt;. Then I run the animation and click a box to have the app spit out all the rotated images for me.&lt;/p&gt;

&lt;p&gt;The output images need a little post-processing, so I use a single Retrobatch workflow to: crop, add transparency, invert, a few other things, and finally stitch the 32 images into one long sprite sheet. (On Windows you can use &lt;a href=&quot;http://photobat.clientside.jp&quot;&gt;Photobat&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-from-3d-to-2d-b.png#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, I run the sprite sheet through a bespoke dithering tool that allows for “live” manual tweaking to convert the greyscale images to 1-bit.&lt;/p&gt;

&lt;p&gt;That’s good enough for my current requirements. Later on I would want extra detail in the renders, either through texturing or by hand.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-from-3d-to-2d-c.png&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;29 May 2020. Soon after I would start rendering the wheels turning and after that the body so it rocks from side to side.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 27 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/27/from-3d-to-2d/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/27/from-3d-to-2d/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Physics</title>
          <description>&lt;p&gt;Now that I was convinced that a driving game could be fun, I was unhappy with the controls and very rudimentary “physics” that the car had. It just didn’t feel very real or compelling; there wasn’t enough depth to the control scheme.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-physics.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So I used &lt;a href=&quot;https://asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html&quot;&gt;Marco Monster’s Car Physics article&lt;/a&gt; (and looked at &lt;a href=&quot;https://github.com/search?q=2d+car+physics&amp;amp;type=repositories&quot;&gt;source code&lt;/a&gt; for various implementations of his technique) to implement more realistic car physics including drifting and skid marks. This was a bit of a watershed moment: this was the game I wanted to spend all my time on.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 24 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/24/physics/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/24/physics/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: Racer</title>
          <description>&lt;p&gt;The Collector prototype didn’t end up being as fun as I had hoped, but I thought it was interestingly that it felt a little like driving. So I wondered whether it would change the feeling by putting some different graphics on top of it. I ripped some temporary graphics from the Atari arcade game Badlands and added one simple collision detection rule and there it was! The first recognisable driving game that would serve as the basis for Daily Driver.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-racer.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;racer&quot;&gt;Racer&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Uses off screen collision map&lt;/li&gt;
  &lt;li&gt;Crank or buttons to steer&lt;/li&gt;
  &lt;li&gt;Buttons to accelerate&lt;/li&gt;
  &lt;li&gt;Variable maximum speeds&lt;/li&gt;
  &lt;li&gt;Lap counter with checkpoints&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 20 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/20/racer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/20/racer/</guid>
        </item>
      
    
      
        <item>
          <title>Daily Driver: The Beginning</title>
          <description>&lt;p&gt;After receiving access to the Playdate SDK I took a while to read the docs, and play around with small code samples, eventually starting to create my own prototypes in April and May 2020. One prototype in particular was the genesis of Daily Driver.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/daily-driver-the-beginning.gif#playdate&quot; alt=&quot;GIF&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;collector&quot;&gt;Collector&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Everything is drawn using graphics primitives (circle, rect, line)&lt;/li&gt;
  &lt;li&gt;Pattern fills rather than pixel dithering&lt;/li&gt;
  &lt;li&gt;Crank or buttons to aim&lt;/li&gt;
&lt;/ul&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 01 May 2020 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2020/05/01/the-beginning/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2020/05/01/the-beginning/</guid>
        </item>
      
    
      
        <item>
          <title>Game Archaeology: No Man’s Sky</title>
          <description>&lt;p&gt;Video game news outlets are currently abuzz with articles about &lt;a href=&quot;https://en.wikipedia.org/wiki/No_Man%27s_Sky&quot;&gt;No Man’s Sky&lt;/a&gt;, one of the most eagerly awaited and massively hyped games in recent years. The game sees you dropped somewhere in space with the goals of exploration, resource management, trading and combat.&lt;/p&gt;

&lt;p&gt;The dubious matter of how closely the released game resembles the one that was hyped over the past few years will no doubt be hotly debated for many months or years to come.&lt;/p&gt;

&lt;p&gt;Regardless, I think the premise of the game is worth talking about because of its influences. Let’s take a trip back through space and time…&lt;/p&gt;

&lt;h2 id=&quot;merchant-of-venus-1982&quot;&gt;Merchant of Venus (1982)&lt;/h2&gt;

&lt;p&gt;The oldest space trading game I know of, this took the form of a menu driven interface where you could buy your first ship and then transport and trade cargo at a number of different spaceports. Very much a resource management game, but with manual landings akin to &lt;a href=&quot;http://www.mobygames.com/game/arcade/lunar-lander__&quot;&gt;Lunar Lander (1979)&lt;/a&gt; that were drawn on screen using groups and combinations of letters from the character set. You can &lt;a href=&quot;http://www.zx81stuff.org.uk/zx81/emulate.php?track=MerchantOfVenus.tzx.zip%400&amp;amp;title=Merchant+of+Venus&quot;&gt;play &lt;em&gt;Merchant of Venus&lt;/em&gt; online now&lt;/a&gt; or &lt;a href=&quot;http://www.mobygames.com/game/merchant-of-venus&quot;&gt;read more about it&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*_LWM7U4tMEuqhXuj-cvJgw.png&quot; alt=&quot;&quot; title=&quot;Merchant of Venus: choosing your ship&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;elite-1984&quot;&gt;Elite (1984)&lt;/h2&gt;

&lt;p&gt;The grandfather of space exploration games: &lt;a href=&quot;https://en.wikipedia.org/wiki/Elite_(video_game)&quot;&gt;Elite&lt;/a&gt;. This featured 3D graphics, a whole procedurally generated Universe (8 galaxies, each containing 256 planets), exploration, trading, combat, hyperspace jumps, manual docking to refuel, missions, multiple ship types and space pirates. All in 32KB of RAM!&lt;/p&gt;

&lt;p&gt;But there was no landing on the surface of planets. Also, somewhat bizarrely, the cassette version lacks the preset missions and has fewer types of ships. You can’t have everything, I suppose.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mobygames.com/game/bbc-micro_/elite&quot;&gt;Read more about the game&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*IZJDEtHnxtQkbdXPR2sQog.png&quot; alt=&quot;&quot; title=&quot;Elite: attempting to dock&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;explorer-1986&quot;&gt;Explorer (1986)&lt;/h2&gt;

&lt;p&gt;We now come to a game that allows exploration on land, thanks to its scenario of crash-landing on an unknown, unexplored planet. The game features an overhead map and procedurally generated screens as you explore the surface, where you make contact with alien species and are able to open portals to get around more easily.&lt;/p&gt;

&lt;p&gt;The graphics were quite impressive for the time, though the fact you’re on one planet was a cunning way to get around the limitations of the procedural generation and the similarities between screens of the various land types. Still worth playing.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mobygames.com/game/zx-spectrum/explorer&quot;&gt;Read more about the game&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*wrpLsl4j7qYehDweLuPrFQ.png&quot; alt=&quot;&quot; title=&quot;Explorer: a procedurally generated planet surface&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;starflight-1986&quot;&gt;Starflight (1986)&lt;/h2&gt;

&lt;p&gt;Whilst Explorer was being released in the UK, over in the USA a development studio called Binary Systems were releasing an all-encompasing space exploration, trading and combat game called Starflight. Arguably even more comprehensive than Elite, it offered exploration, trading, combat but graphically was missing 3D graphics instead going for a hybrid menu-based system with panels of 2D animated graphics to give context to the current objective.&lt;/p&gt;

&lt;p&gt;It was released on a range of 8-bit and 16-bit home computers, and also the &lt;a href=&quot;https://en.wikipedia.org/wiki/Sega_Genesis&quot;&gt;Sega Genesis/Mega Drive&lt;/a&gt;. Game designer &lt;a href=&quot;https://en.wikipedia.org/wiki/Greg_Johnson_(game_designer)&quot;&gt;Greg Johnson&lt;/a&gt; went on to co-create the cult &lt;a href=&quot;https://en.wikipedia.org/wiki/ToeJam_%26_Earl&quot;&gt;ToeJam &amp;amp; Earl&lt;/a&gt; series of games. But, for me, Starflight is his &lt;a href=&quot;https://en.wikipedia.org/wiki/Magnum_opus&quot;&gt;magnum opus&lt;/a&gt;. It’s easy to &lt;a href=&quot;https://www.gog.com/game/starflight_1_2&quot;&gt;play the game (and its sequel) today on PC thanks to a re-release by GOG&lt;/a&gt;  or &lt;a href=&quot;http://www.mobygames.com/game/dos/starflight&quot;&gt;read more about it&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*vpjQoieWmqTkk0Oc_u_rgA.png&quot; alt=&quot;&quot; title=&quot;Starflight: docking in progress&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;starglider-2-1988&quot;&gt;Starglider 2 (1988)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Argonaut_Games&quot;&gt;Argonaut Games&lt;/a&gt;, a studio best known for creating &lt;a href=&quot;https://en.wikipedia.org/wiki/Star_Fox_(video_game)&quot;&gt;Star Fox&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Super_FX&quot;&gt;Super FX&lt;/a&gt; coprocessor chip with/for Nintendo, have an interesting part to play in this story. They’d forged ahead with software-driven 3D engines on computers that had very limited processing power, culminating in &lt;a href=&quot;https://en.wikipedia.org/wiki/Starglider_2&quot;&gt;Starglider 2&lt;/a&gt; for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Amiga&quot;&gt;Amiga&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Atari_ST&quot;&gt;Atari ST&lt;/a&gt; and PC. A tour de force of cutting edge technology, the game allowed exploration of a solar system, planetary surfaces and everywhere in between. Whilst it was set in an open world, the game featured a plot and overall goal for the player: to collect the parts of a neutron bomb and use it to blow up an enemy space station.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mobygames.com/game/atari-st/starglider-2&quot;&gt;Read more about the game&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*HGOyD_2zW6YD-Ueh0vdjkg.png&quot; alt=&quot;&quot; title=&quot;Starglider 2: rudely interrupted by some space pirates&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;hunter-1991&quot;&gt;Hunter (1991)&lt;/h2&gt;

&lt;p&gt;The final game I want to mention doesn’t involve space, but it does involve a huge open world to be explored and a mission to complete. &lt;a href=&quot;https://en.wikipedia.org/wiki/Hunter_(video_game)&quot;&gt;Hunter&lt;/a&gt; was the perfect example of an open world game where you could use many different types of transport to get around the world, from bicycles to boats and helicopters. You could enter buildings, amass an inventory of collected items that can be used to solve puzzles and progress towards your ultimate goal.&lt;/p&gt;

&lt;p&gt;The game had three modes: &lt;em&gt;Hunter&lt;/em&gt; (a long story-based mission), &lt;em&gt;Missions&lt;/em&gt; (a series of smaller missions), and &lt;em&gt;Action&lt;/em&gt; (against the clock search and destroy around the map). The game was the most convincing depiction of a real world I had seen at that point, and remained that way for some years until the often compared &lt;a href=&quot;https://en.wikipedia.org/wiki/Grand_Theft_Auto&quot;&gt;Grand Theft Auto series&lt;/a&gt; of games.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mobygames.com/game/hunter&quot;&gt;Read more about the game&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*yipfL0Qm7KNYyMKNxgcUgw.png&quot; alt=&quot;&quot; title=&quot;Hunter: you have boarded a bicycle&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;no-mans-sky-2016&quot;&gt;No Man’s Sky (2016)&lt;/h2&gt;

&lt;p&gt;My hopes for &lt;a href=&quot;https://en.wikipedia.org/wiki/No_Man&apos;s_Sky&quot;&gt;No Man’s Sky&lt;/a&gt; were that it would combine the best features of all the space exploration games that went before it. It could take the Universe, trading, combat and missions from &lt;em&gt;Elite&lt;/em&gt;; procedural generation from &lt;em&gt;Explorer&lt;/em&gt;; plot-driven goal from &lt;em&gt;Starglider 2&lt;/em&gt;; the land exploration and variety of vehicles in &lt;em&gt;Hunter&lt;/em&gt;. Heck, maybe it would just be &lt;em&gt;Starflight&lt;/em&gt; with a veneer of wonderful 3D graphics.&lt;/p&gt;

&lt;p&gt;But the released version of &lt;em&gt;No Man’s Sky&lt;/em&gt; is different. Whilst it has all the trappings of a great game, it falls short in several key areas: balance, plot and—most importantly of all—gameplay. So, in a lot of ways the game is actually no more advanced than the 30-or-so year old games I’ve mentioned.&lt;/p&gt;

&lt;p&gt;Stylistically, of course, &lt;em&gt;No Man’s Sky&lt;/em&gt; is light years ahead. Gameplay wise it’s no better than &lt;em&gt;Elite&lt;/em&gt; or &lt;em&gt;Starglider 2&lt;/em&gt;, in fact it could be described as being worse. It appears to be rushed, hurried, incomplete, unbalanced.&lt;/p&gt;

&lt;p&gt;Most interestingly, the released game lacks a host of features that had been repeatedly mentioned to the press and shown to the public over the last several years. It almost seems as if they’ve chopped huge important chunks off the game in the last few months.&lt;/p&gt;

&lt;h1 id=&quot;the-gameplay-is-in-another-galaxy&quot;&gt;The Gameplay is in Another Galaxy&lt;/h1&gt;

&lt;p&gt;So what happens next? In my experience it’s uncommon for such deficiencies in the game to be patched or updated after a few initial patches that correct serious bugs and game-breaking features.&lt;/p&gt;

&lt;p&gt;To that end, I wouldn’t be surprised if &lt;a href=&quot;https://twitter.com/NoMansSky&quot;&gt;Hello Games&lt;/a&gt; and Sony roll out a different—more and capable—version of &lt;em&gt;No Man’s Sky&lt;/em&gt; for the soon to be revealed &lt;a href=&quot;https://www.google.co.uk/search?q=PlayStation+4+Neo&quot;&gt;PlayStation 4 Neo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In a funny way that would make the game even closer to &lt;em&gt;Elite&lt;/em&gt; with a different game depending on the platform you choose to play it on.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 19 Aug 2016 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2016/08/19/game-archaeology-no-mans-sky/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2016/08/19/game-archaeology-no-mans-sky/</guid>
        </item>
      
    
      
        <item>
          <title>Game Archaeology: Rocket League</title>
          <description>&lt;p&gt;One of the most successful console games of 2016 has been &lt;a href=&quot;http://www.rocketleaguegame.com/&quot;&gt;Rocket League&lt;/a&gt;. It features cars playing football (soccer) rather than people. Cool!&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;r4iT0yZEwk8&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;Some would say it’s both a surprise hit, apparently coming out of nowhere, and also a novel concept. A while go I was chatting with &lt;a href=&quot;http://www.spaceapegames.com/about/board-of-directors/&quot;&gt;Simon Hade&lt;/a&gt;, COO and Co-Founder of &lt;a href=&quot;http://www.spaceapegames.com/&quot;&gt;Space Ape Games&lt;/a&gt;, who made exactly these observations. At this point the game librarian in me couldn’t help but correct him, so I mentioned that it wasn’t novel at all. 😱&lt;/p&gt;

&lt;p&gt;During my formative years I had played a game called &lt;a href=&quot;http://www.mobygames.com/game/wild-wheels&quot;&gt;Wild Wheels&lt;/a&gt; on my teenage crush computer—the Atari ST—some time around 1990, and I’d also played Konami’s &lt;a href=&quot;https://en.wikipedia.org/wiki/GTI_Club&quot;&gt;GTi Club&lt;/a&gt; on my Wii in 2010. Both of these games offer a take on car soccer, and I was sure there had to be even more car soccer games I wasn’t aware of.&lt;/p&gt;

&lt;p&gt;On my way home I put together a list. I do love lists.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.mobygames.com/game-group/ball-sports-with-vehicles&quot;&gt;www.mobygames.com/game-group/ball-sports-with-vehicles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that Rocket League is the latest in a long line of car soccer games, and the sequel of &lt;a href=&quot;https://en.wikipedia.org/wiki/Supersonic_Acrobatic_Rocket-Powered_Battle-Cars&quot;&gt;Supersonic Acrobatic Rocket-Powered Battle-Cars&lt;/a&gt; from seven years prior. The earliest game of this type is from 1977 and there are at least a couple of dozen others between then and Rocket League.&lt;/p&gt;

&lt;h2 id=&quot;the-secret-of-success&quot;&gt;The Secret of Success&lt;/h2&gt;

&lt;p&gt;So what made Rocket League a success in light of all the preceding games? Perhaps it was a well executed online mode? But you could then argue that half of the games in the list also had online play.&lt;/p&gt;

&lt;p&gt;The most important differentiator is that &lt;em&gt;Rocket League&lt;/em&gt; was released on the right platforms to target the right users. The trifecta of PS4/PC/Xbox One means every platform that is home to those “hardcore” gamers who play online seriously. In that respect I think of Rocket League as being more similar to FIFA than you might first expect.&lt;/p&gt;

&lt;p&gt;Apparently there are signs of life outside of mobile after all.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 01 Jul 2016 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2016/07/01/game-archaeology-rocket-league/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2016/07/01/game-archaeology-rocket-league/</guid>
        </item>
      
    
      
        <item>
          <title>Game Critique: Frantic Architect</title>
          <description>&lt;p&gt;&lt;a href=&quot;https://itunes.apple.com/gb/app/frantic-architect/id1062825120?mt=8&quot;&gt;Frantic Architect&lt;/a&gt; for iOS and Android is a great casual game by &lt;a href=&quot;https://bulkypix.com/games/frantic-architect/&quot;&gt;Will Kwan/BulkyPix&lt;/a&gt; in which you have to build as tall a tower as possible, with the kicker being that you have limited control of where exactly the next building block will go. A video will help explain better:&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;hkLiQ17KNRE&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;The game has a high degree of polish and the user interface design and screen layout is excellent. However, play of more than a few minutes will lead to frustration, which is something that really needs to be managed by the developer. Too much frustration and the player will go away and never open the game again.&lt;/p&gt;

&lt;p&gt;I think there’s one change that could be made that would make the game easier and less frustrating to play:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The block should lock into place on the “touch up” event, rather than on the “touch down” event as it is now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This simple change would enable the player to reduce their reaction time by keeping their finger on the screen until they exact moment they want to lock a block in place.&lt;/p&gt;

&lt;p&gt;The physical movement of lifting the finger off the screen is a lot faster than the the double movement of first touching the screen followed by lifting the finger off again.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 10 Jun 2016 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2016/06/10/game-critique-frantic-architect/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2016/06/10/game-critique-frantic-architect/</guid>
        </item>
      
    
      
        <item>
          <title>Game Critique: Hill Racer 2</title>
          <description>&lt;p&gt;&lt;em&gt;From time to time I’ll be posting critique of video games in this way. It’s meant as constrictive criticsm in the nicest possible way. It also goes to show the type of feedback I give to developers when asked to test or review their games.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Recently I’ve been playing a fair bit of &lt;a href=&quot;https://itunes.apple.com/gb/app/hill-racer-2-extreme-speed/id946433365?mt=8&quot;&gt;Hill Racer 2&lt;/a&gt; on my Apple TV. It’s kind of like &lt;a href=&quot;https://itunes.apple.com/gb/app/tiny-wings/id417817520?mt=8&quot;&gt;Tiny Wings&lt;/a&gt;, but with cars. Right up my street! Check it out:&lt;/p&gt;

&lt;lite-youtube style=&quot;aspect-ratio: 16/9;&quot; videoid=&quot;3fPDJZz3whY&quot; params=&quot;start=0&amp;amp;modestbranding=2&quot;&gt;
&lt;/lite-youtube&gt;

&lt;p&gt;It’s quite well done, but there are a few small details that the developers could look at to easily improve both user experience and engagement.&lt;/p&gt;

&lt;h2 id=&quot;game-over-man&quot;&gt;Game over, man!&lt;/h2&gt;

&lt;p&gt;When you run out of gas (or petrol as we say in the UK) the game ends immediately. This is quite jarring, and it would be much better if the accelerator stopped working and the car could then slowly come to a halt under its own moment. The benefit of this would be twofold:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the experience would be smoother and less jarring for the player,&lt;/li&gt;
  &lt;li&gt;the player stands a chance of reclaiming their game as they might be able to reach the next checkpoint even when they have run out of fuel. I have fond memories of clinching victory from the jaws of defeat like this in SEGA’s arcade classic &lt;a href=&quot;https://en.wikipedia.org/wiki/Out_Run&quot;&gt;Out Run&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;caught-in-a-trap&quot;&gt;Caught in a trap&lt;/h2&gt;

&lt;p&gt;Once you upgrade your car a few times you’ll have quite a decent top speed. This should be a good thing, but in fact it’s not. This is because the car body moves about a bit and can actually get stuck in bridges as you drive across them. This should be an easy fix by adjusting the collision of bridges against the car body only whilst the wheels are touching it.&lt;/p&gt;

&lt;h2 id=&quot;grinder&quot;&gt;Grinder&lt;/h2&gt;

&lt;p&gt;You can tell that the game is an iOS port, as it’s built around &lt;a href=&quot;https://en.wikipedia.org/wiki/Grinding_%28video_gaming%29&quot;&gt;grinding&lt;/a&gt;, in this case that’s earning in-game currency to be able to upgrade your car or buy a new one. On iOS this keeps users in the game and means that the developer can run more ads, and earn more money. On Apple TV ads in games are not an option, so I think the developer should have rebalanced the game to favour less grinding. This last one is a judgment call, though, as it would mean the game would be different across platforms.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2016/06/09/game-critique-hill-racer-2/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2016/06/09/game-critique-hill-racer-2/</guid>
        </item>
      
    
      
        <item>
          <title>Game Analysis: Boom Dots</title>
          <description>&lt;p&gt;&lt;em&gt;One thing I occasionally do is a sort of third-person-post-mortem of a game I’ve been playing a lot of. I think about how it might have been put together from a game design and programming perspective. Of course this sort of analysis is just my opinion, but I do try to think things through far enough to prove my point. Often I go so far as to recreate the core game mechanic as a rapid prototype, just to be sure that my thinking is correct.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://umbrella.wtf/boomdots/&quot;&gt;Boom Dots by Umbrella Games&lt;/a&gt; is a great minimalist, arcade-style game that has enjoyed continued success on the App Store. What struck me about the game—other than how well it has been put together—was how simple and elegant the concept is. I see it as a simplified version of Space Invaders. The developer has sucessfully reduced an already simple concept to its bare essentials, doing away with both player movement and enemy formation in the process. You might think that removing those two keys elements would remove the fun, but you’d be wrong. I think it actually &lt;em&gt;amplifies&lt;/em&gt; the fun!&lt;/p&gt;

&lt;p&gt;Anyway, I was playing Boom Dots, marvelling at the elegance of the concept and wishing I’d come up with it first, and I began to think about how it might be put together. That’s either a blessing or a curse, but I can’t help but think about games in that way after they get a hold of me. Boom Dots is a great game with which to start this occasional series of posts, as it’s a very simple mechanic.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There’s an Enemy Dot. And there’s a Player Dot.&lt;/p&gt;

  &lt;p&gt;The Player Dot can be released at which point it will move upwards. Meanwhile the Enemy Dot is moving back and forth across the screen.&lt;/p&gt;

  &lt;p&gt;If the Dots collide, you score and a new Enemy Dot appears. If you miss, it’s Game Over.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Testing whether the two dots, or circles, overlap is as easy as testing whether the distance between their centre points is less than the sum of their respective radiuses. A little bit of trigonometry is required. Easy.&lt;/p&gt;

&lt;p&gt;Tapping the Player Dot gives it some velocity to it, and sends it on its way. Super easy.&lt;/p&gt;

&lt;p&gt;Now to the Enemy Dot. The way this comes on the screen is really nice: such a smooth curve! And the way it moves back and forth: so smooth! Surely this is difficult to replicate? Well, yes, if you’re doing it from scratch. But absolutely not if you have the ability to perform &lt;a href=&quot;https://en.wikipedia.org/wiki/Inbetweening&quot;&gt;tweening&lt;/a&gt; animations, which I tend to do using a set of tried and tested &lt;a href=&quot;http://easings.net&quot;&gt;Easing functions&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Easing functions allow you to specify a curve that the speed of the animation should follow on its way from the start value to the end value. Normally it would move at a constant speed from start to end: Linear. But by adjusting the how fast we go using a mathematical formula, we can make the animation play at a different speeds depending on how far along between we are.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perfect.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Types of curves that can be applied in this way are: Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential and Circular. Then there’s even Elastic and Bounce, which add a bit of wobble to proceedings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Easings are easier to understand by looking at &lt;a href=&quot;http://easings.net&quot;&gt;interactive visualisations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, back to the Enemy Dot moving side to side. We want the animation to start slowly, speed up, then slow down. Looking at the visualisations we see that easeInOutSine will do that, and it’s not as severe as some of the others so it’d be a good one to try first. By applying the easeInOutSine Easing function to the Enemy Dot as it travels back and forth we can get just the effect we require. We can apply a similar function to animate the dot as it comes down onto the screen. When both animations happen at once a smooth curve emerges—mathematics is great!&lt;/p&gt;

&lt;p&gt;At its core Boom Dots is as easy as that: two tweens, some velocity on tap, and a simple collision detection check. Cool, huh?&lt;/p&gt;

&lt;p&gt;That’s all well and good, but there’s only one way to really know if the analysis is correct: to make a game that way. So that’s what I did.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.gingerbeardman.com/boomdots/&quot;&gt;Play the game right now in your browser&lt;/a&gt; or &lt;a href=&quot;https://vimeo.com/169931918&quot;&gt;watch a short video of it&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://miro.medium.com/max/750/1*AHPucF97JYxZj2uJC8FfNA.png&quot; alt=&quot;&quot; title=&quot;Add the game to your iPhone home screen for the best experience.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I chose the &lt;a href=&quot;http://phaser.io&quot;&gt;Phaser JavaScript framework&lt;/a&gt; for this particular prototype. I’d been reading its documentation and it looked well suited to the task at hand. For example, it has the Easing functions that I wanted to use to get the dots moving smoothly. SpriteKit, to contrast, doesn’t have built-in Easing functions—though of course you could write your own or port some code across if you wanted to do this natively on iOS. I tend to experiment with a variety of frameworks and tools just to keep things interesting.&lt;/p&gt;

&lt;p&gt;Phaser is great because it takes care of the dull boilerplate work enabling you to concentrate on the actual game. It uses WebGL or the HTML Canvas depending on what is best for the device it is running on, and also provides some useful shortcuts for loading of assets, managing game states, easily adding physics and lots more. Explosions, for another example, also come for free. I used a small plugin to add the “screen shake” effect. The circle-to-circle collision I talked about earlier is also made even easier using Phaser:&lt;/p&gt;

&lt;p&gt;Is the distance between the two centre points less than the sum of the two radiuses?&lt;/p&gt;

&lt;p&gt;The prototype took me a few hours from start to finish, with another few the following day balancing, polishing and adding high score saving. I tend to do these reconstructions a few times a year, mostly on Bank Holidays.&lt;/p&gt;

&lt;p&gt;The complete source code for my version of Boom Dots is &lt;a href=&quot;https://github.com/gingerbeardman/boomdots&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, Boom Dots goes a lot further than the core simple mechanic. It has a thick layer of presentation varnish. It tracks every bit of gameplay and uses them to give a steady stream of meta challenges to the player. These “missions” encourage the player to approach the game in different ways; to achieve certain goals in the gameplay such as getting a perfect hit, or surviving for a certain amount of time. It also introduces graphical themes that can be unlocked with extended play. These things keep the player in the game and the developer earning money through ads and in-app purchases.&lt;/p&gt;

&lt;p&gt;The developer, &lt;a href=&quot;https://twitter.com/mudloop&quot;&gt;Sven Magnus&lt;/a&gt;, certainly knows how to &lt;a href=&quot;http://www.youtube.com/watch?v=Fy0aCDmgnxg&quot;&gt;juice up a game&lt;/a&gt;. That’s a topic for another post.&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 01 Jun 2016 00:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2016/06/01/game-analysis-boom-dots/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2016/06/01/game-analysis-boom-dots/</guid>
        </item>
      
    
      
        <item>
          <title>Boom Matt</title>
          <description>&lt;p&gt;This is my version of the mobile game &lt;a href=&quot;/2016/06/01/game-analysis-boom-dots/&quot;&gt;Boom Dots by Umbrella Games&lt;/a&gt;, made this one Saturday evening in 2015 using Phaser HTML5 game framework just to see what it was like.&lt;/p&gt;

&lt;p&gt;Works on mobile, of course.&lt;/p&gt;

&lt;p&gt;Play in your browser: &lt;a href=&quot;https://gingerbeardman.itch.io/boom-matt&quot;&gt;gingerbeardman.itch.io/boom-matt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/boom-matt-title.png&quot; alt=&quot;IMG&quot; /&gt; &lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/boom-matt-game.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sat, 14 Mar 2015 23:59:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2015/03/14/boom-matt/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2015/03/14/boom-matt/</guid>
        </item>
      
    
      
        <item>
          <title>Wire Hang Redux: update</title>
          <description>&lt;p&gt;An update to Wire Hang Redux my version of the Java game Wire Hang, with improved controls and graphics. This version was built using BlitzMax.&lt;/p&gt;

&lt;p&gt;Read more about the game in the original &lt;a href=&quot;/2004/06/20/wire-hang-redux/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://gingerbeardman.itch.io/wire-hang-redux&quot;&gt;gingerbeardman.itch.io/wire-hang-redux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-title.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-clouds.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wire-hang-redux-update-stars.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Mon, 12 Dec 2011 14:54:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2011/12/12/wire-hang-redux-update/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2011/12/12/wire-hang-redux-update/</guid>
        </item>
      
    
      
        <item>
          <title>Wire Hang Redux</title>
          <description>&lt;p&gt;I made a new game! It’s a from-scratch remake of an original Java game, Wire Hang, by &lt;a href=&quot;https://www.mobygames.com/person/510170/masaki-kobayashi/&quot;&gt;Masaki Kobayashi&lt;/a&gt; (D2AC) who went on to become part of the Gran Turismo team.&lt;/p&gt;

&lt;p&gt;I had a pretty underpowered laptop at the time, and writing my own version of the game was the only way I was able to play it comfortably.&lt;/p&gt;

&lt;p&gt;My version of the game, Wire Hang Redux—made with Kobayshi-san’s blessing—went onto to receive over one million downloads from early download sites like &lt;a href=&quot;https://en.wikipedia.org/wiki/Tucows&quot;&gt;Tucows&lt;/a&gt;, Version Tracker, Download.com, Mac Update, &lt;a href=&quot;https://en.wikipedia.org/wiki/Home_of_the_Underdogs&quot;&gt;Home of the Underdogs&lt;/a&gt;, Game Hippo, &lt;a href=&quot;http://osx.hyperjeff.net/Apps/apps?f=wire%20hang%20redux&quot;&gt;Hyper Jeff&lt;/a&gt;, &lt;a href=&quot;https://web.archive.org/web/20040710054651/http://www.forest.impress.co.jp/article/2004/07/06/wirehangredux.html&quot;&gt;Windows Forest&lt;/a&gt; (Japan), and even a little website called &lt;a href=&quot;https://web.archive.org/web/20050302140236/http://www.apple.com/downloads/macosx/games/action_adventure/wirehangredux.html&quot;&gt;Apple.com&lt;/a&gt;—back when it had a download section! It was featured in computer magazines all around the world.&lt;/p&gt;

&lt;p&gt;Archived web page: &lt;a href=&quot;https://www.gingerbeardman.com/archive/wirehang/&quot;&gt;gingerbeardman.com/archive/wirehang/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://gingerbeardman.itch.io/wire-hang-redux&quot;&gt;gingerbeardman.itch.io/wire-hang-redux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wirehangredux_title.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wirehangredux_game.png&quot; alt=&quot;IMG&quot; /&gt;
&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/wirehangredux_score.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Sun, 20 Jun 2004 00:34:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2004/06/20/wire-hang-redux/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2004/06/20/wire-hang-redux/</guid>
        </item>
      
    
      
        <item>
          <title>Circuit Heat</title>
          <description>&lt;p&gt;I made a prototype of a game called Circuit Heat. It is a version of the classic network completion puzzle (aka Pipes, FreeNet, Net, NetWalk, etc). The graphics remind me a little of the Atari Lynx classic puzzler Chip’s Challenge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;At this time, long before iPhone, I was playing Java games on a (Sagem?) cell phone so many of my concepts around this time were targeted at that sort of platform&lt;/li&gt;
  &lt;li&gt;The game was was later featured on &lt;a href=&quot;https://discmaster.textfiles.com/browse/42140/PCF161DVD_05_04/PCF161DVD_05_04.ISO/Gamemaker/Blitz%20Research%20Demo%20Disk/DemoDisk1%20Files/Puzzle/CircuitHeat&quot;&gt;PC Format 161 (May 2004) cover disc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h2&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/circuit-heat-title.png&quot; alt=&quot;PNG&quot; title=&quot;Title screen&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/circuit-heat-game.png&quot; alt=&quot;PNG&quot; title=&quot;In-game, level complete&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Thu, 23 Jan 2003 12:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2003/01/23/circuit-heat/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2003/01/23/circuit-heat/</guid>
        </item>
      
    
      
        <item>
          <title>Terra Firma</title>
          <description>&lt;p&gt;This is my entry into the BlitzCoder Stupidest Game Competition, 2002. You need to guide a sky diver—whose parachute has failed—past obstacles and attempt to land on a cow. Fun!&lt;/p&gt;

&lt;p&gt;It was written using BlitzBasic and later recompiled in BlitzPlus.&lt;/p&gt;

&lt;p&gt;This is the game that made me realise I could make games.&lt;/p&gt;

&lt;p&gt;Archived web page: &lt;a href=&quot;https://www.gingerbeardman.com/archive/terrafirma/&quot;&gt;gingerbeardman.com/archive/terrafirma/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://gingerbeardman.itch.io/terra-firma&quot;&gt;gingerbeardman.itch.io/terra-firma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/terra-firma-title.png&quot; alt=&quot;IMG&quot; /&gt; &lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/terra-firma-ufo.png&quot; alt=&quot;IMG&quot; /&gt; &lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/terra-firma-cow.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 23 Aug 2002 11:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2002/08/23/terra-firma/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2002/08/23/terra-firma/</guid>
        </item>
      
    
      
        <item>
          <title>Yaking</title>
          <description>&lt;p&gt;A small prototype for a kayak/canoe “simulator” game, featuring water currents, a gate to paddle through, and somewhat unique paddling controls (press left/right alternately).&lt;/p&gt;

&lt;p&gt;Made using BlitzBasic and targetting Game Boy Advance resolution of 240×160.&lt;/p&gt;

&lt;p&gt;Archived web page: &lt;a href=&quot;https://www.gingerbeardman.com/archive/yaking/&quot;&gt;gingerbeardman.com/archive/yaking/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download: &lt;a href=&quot;https://gingerbeardman.itch.io/yaking&quot;&gt;gingerbeardman.itch.io/yaking&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/yaking.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 27 Mar 2002 12:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2002/03/27/yaking/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2002/03/27/yaking/</guid>
        </item>
      
    
      
        <item>
          <title>Bendertron</title>
          <description>&lt;p&gt;This is my Futurama-themed fan-game inspired a little by the Williams arcade classic Robotron and a lot by Jeff Minter’s Llamatron. Written in BlitzBasic for Windows 9x.&lt;/p&gt;

&lt;p&gt;Created in Feb/Mar 2001 during the dot-com boom and released in Jan 2002 after the bubble burst!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Explosion animation by the wonderful &lt;a href=&quot;https://www.amelines.com&quot;&gt;Alex Amelines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Sounds and graphics ripped from the TV show&lt;/li&gt;
  &lt;li&gt;It’s a 25-year-old free fan-game, you know?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Play it on an old install of Windows, or on modern Windows using &lt;a href=&quot;https://sourceforge.net/projects/dxwnd/&quot;&gt;DxWnd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Free Download: &lt;a href=&quot;https://gingerbeardman.itch.io/bendertron&quot;&gt;gingerbeardman.itch.io/bendertron&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bendertron-game.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/bendertron-title.png&quot; alt=&quot;IMG&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Wed, 14 Feb 2001 14:11:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2001/02/14/bendertron/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2001/02/14/bendertron/</guid>
        </item>
      
    
      
        <item>
          <title>Simple Soccer</title>
          <description>&lt;p&gt;Simple Soccer is my take on the classic Sensible Soccer. It was written in BlitzBasic and ran at 800×600 under Windows 9x.&lt;/p&gt;

&lt;p&gt;I built multiple parts—player control, dribbling, cpu and formation, goalkeeper behaviour—but never managed to combine it all in a finished game. Still, I count it as my first real game.&lt;/p&gt;

&lt;p&gt;Archived web page: &lt;a href=&quot;https://www.gingerbeardman.com/archive/soccer/&quot;&gt;gingerbeardman.com/archive/soccer/&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;tofigure&quot;&gt;&lt;img src=&quot;https://cdn.gingerbeardman.com/images/posts/simple-soccer.png&quot; alt=&quot;IMG&quot; title=&quot;The beautiful game&quot; /&gt;&lt;/p&gt;
</description>
          <author>by Matt Sephton</author>
          <pubDate>Fri, 29 Sep 2000 11:00:00 +0000</pubDate>
          <link>https://blog.gingerbeardman.com/2000/09/29/simple-soccer/</link>
          <guid isPermaLink="true">https://blog.gingerbeardman.com/2000/09/29/simple-soccer/</guid>
        </item>
      
    

  </channel>
</rss>
