<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Afterschool Studio]]></title><description><![CDATA[Afterschool is a videogame development studio dedicated to creating aesthetically ambitious, systems-driven games.]]></description><link>https://afterschool.studio</link><image><url>https://substackcdn.com/image/fetch/$s_!iobI!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3beb45a-631e-4a0a-9d93-56b291eaefad_277x277.png</url><title>Afterschool Studio</title><link>https://afterschool.studio</link></image><generator>Substack</generator><lastBuildDate>Wed, 22 Apr 2026 12:08:09 GMT</lastBuildDate><atom:link href="https://afterschool.studio/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Kyle Kukshtel]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[afterschoolstudio@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[afterschoolstudio@substack.com]]></itunes:email><itunes:name><![CDATA[Kyle Kukshtel]]></itunes:name></itunes:owner><itunes:author><![CDATA[Kyle Kukshtel]]></itunes:author><googleplay:owner><![CDATA[afterschoolstudio@substack.com]]></googleplay:owner><googleplay:email><![CDATA[afterschoolstudio@substack.com]]></googleplay:email><googleplay:author><![CDATA[Kyle Kukshtel]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Dinghy Year End 2023]]></title><description><![CDATA[Dear ImGui integration, a new Scene system, and some demo videos!]]></description><link>https://afterschool.studio/p/dinghy-year-end-2023</link><guid isPermaLink="false">https://afterschool.studio/p/dinghy-year-end-2023</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Tue, 02 Jan 2024 16:15:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s67P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s67P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s67P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 424w, https://substackcdn.com/image/fetch/$s_!s67P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 848w, https://substackcdn.com/image/fetch/$s_!s67P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 1272w, https://substackcdn.com/image/fetch/$s_!s67P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s67P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png" width="728" height="408" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:816,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!s67P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 424w, https://substackcdn.com/image/fetch/$s_!s67P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 848w, https://substackcdn.com/image/fetch/$s_!s67P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 1272w, https://substackcdn.com/image/fetch/$s_!s67P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8bc3b3f-7dee-4ff9-b3f5-4b7708d3893d_1456x816.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As 2023 comes to a close I'm really satisfied with where I've been able to bring Dinghy. I'm over the hump of the initial startup cost of just figuring out how to <em>do</em> everything, and given it's trim, code-only nature, it means that working on it now is often just a matter of pulling together threads that already exist in the development workflow/API, adding a little bit new, and then having tangible progress.</p><p>The place this manifests most is through the current driving paradigm of Dinghy's development &#8212; demo samples. I think this is most inspired by <a href="https://haxeflixel.com/demos/">HaxeFlixel's demos page</a> but also especially <a href="https://heaps.io/samples/">Heaps' demos page</a> and <a href="https://floooh.github.io/sokol-html5/">Sokol's samples page</a>. The idea is simple &#8212; enumerate major functionality through single purpose demos. The demos act not only as API examples, but also help to teach "ergonomics" around the engine/API and show how they are all intended to be used together. Developing them also acts as nice little coding exercises that see you actually "using" the engine, and allowing you to question your own biases around the development process and tweak the experience of working with the engine to better approach the target "feeling".</p><p>Currently, there are 14 demos in Dinghy that represent core functionality:</p><ol><li><p>Texture - Shows how to load in a texture and show it on screen</p></li><li><p>Texture Frame - Shows how to load in a texture and show only a portion of it ("Frame") on screen.</p></li><li><p>Animation - Shows how to load in a texture and slice it for animation playback.</p></li><li><p>Simple Update - Basic demo showing how to use an update loop.</p></li><li><p>Interaction - Shows how to tie into the input system for feedback</p></li><li><p>Bunnymark - Smoke test benchmark</p></li><li><p>Physics - Shows how to setup entities for use in a physics system (uses Volatile physics)</p></li><li><p>Shape - Shows how to spawn a simple shape for an entity (basically a textureless GL_Primitive type object)</p></li><li><p>Physics Shape - same as physics demo but uses shapes</p></li><li><p>Entity Emitter - Just shows how to spawn lots of entities</p></li><li><p>Collision - Shows how to do things like mouseover for entities as well as find closest contact point, etc.</p></li><li><p>Grid - Shows example of using the grid class to spawn entities in a user-specific grid</p></li><li><p>Particle System - Demonstrates the particle system in the engine</p></li></ol><p>At first, each demo was just a function in a top level program, and running them was a matter of commenting/uncommenting the specific demo and rebuilding the project.</p><p>This was okay at first, but as the number of demos started to climb it became a bit unwieldy. You can still write Dinghy games fully in a single file (and I recommend you do so for small stuff!) but I realized I needed a better organizational scheme. Additionally, I wanted to be able to switch demos at runtime, which also meant the ability to setup/teardown demos as well as the interface for navigating between them.</p><p>These two constraints led the two other major efforts of the past few months since the last update &#8212;the creation of a scene system and integration with Dear Imgui.</p><p>Before I got into the specifics, I&#8217;ll show the end result. Here's me just navigating through the demos one by one in Dinghy:</p><div id="youtube2-rgyOkpba4ME" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;rgyOkpba4ME&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/rgyOkpba4ME?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Pretty nice!</p><p>The scene system is inspired a bit by <a href="https://ceramic-engine.com/guides/scenes/">Ceramic&#8217;s scene system</a>, and works in the ECS like anything else. This was definitely a big "rubber meets the road" moment as well for deciding if Dinghy was going to truly be only code. There are obvious ways for scenes to just be data and have them configured at runtime a la Unity, but instead of going down that path I wanted to maintain that Dinghy was code-only and as such chose a more OOP model for Scenes (instead of data). You could still totally build a runtime scene editor to plug into the scene system, but out of the box I&#8217;m providing a strongly typed object and some utility functions to configure scenes and their lifecycles. Here's a code example of a scene (the basic Texture demo):</p><pre><code>namespace Dinghy.Sandbox.Demos;
&#8203;
[DemoScene("01 Texture")]
public class Texture : Scene
{
 &nbsp; &nbsp;private TextureData conscriptImage;
 &nbsp; &nbsp;private SpriteData fullConscript;
 &nbsp; &nbsp;public override void Preload()
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;conscriptImage = new TextureData("conscript.png");
 &nbsp; &nbsp; &nbsp; &nbsp;fullConscript = new(conscriptImage);
 &nbsp;  }
&#8203;
 &nbsp; &nbsp;public override void Create()
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;Engine.SetTargetScene(this);
 &nbsp; &nbsp; &nbsp; &nbsp;new Sprite(fullConscript);
 &nbsp;  }
}</code></pre><p>Scenes also do provide Update hooks for objects (the SimpleUpdate example):</p><pre><code>using Dinghy.Core;
&#8203;
namespace Dinghy.Sandbox.Demos;
&#8203;
[DemoScene("04 Simple Update")]
public class SimpleUpdate : Scene
{
 &nbsp; &nbsp;private TextureData conscriptImage;
 &nbsp; &nbsp;private SpriteData conscriptFrame0;
 &nbsp; &nbsp;public override void Preload()
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;conscriptImage = new TextureData("conscript.png");
 &nbsp; &nbsp; &nbsp; &nbsp;conscriptFrame0 = new(conscriptImage, new Frame(0,0,64,64));
 &nbsp;  }
&#8203;
 &nbsp; &nbsp;Sprite e;
 &nbsp; &nbsp;Point startPos = (0,0);
 &nbsp; &nbsp;public override void Create()
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;Engine.SetTargetScene(this);
 &nbsp; &nbsp; &nbsp; &nbsp;startPos = ((Engine.Width / 2f) - 32, (Engine.Height / 2f) - 32);
 &nbsp; &nbsp; &nbsp; &nbsp;e = new Sprite(conscriptFrame0)
 &nbsp; &nbsp; &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;X = (int)startPos.X,
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Y = (int)startPos.Y,
 &nbsp; &nbsp; &nbsp;  };
 &nbsp;  }
&#8203;
 &nbsp; &nbsp;public override void Update(double dt)
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;e.X = (int)startPos.X + (int)(Math.Sin(Engine.Time) * 100);
 &nbsp; &nbsp; &nbsp; &nbsp;e.Rotation = (float)Engine.Time;
 &nbsp; &nbsp; &nbsp; &nbsp;var scale = (Math.Cos(Engine.Time) * 2);
 &nbsp; &nbsp; &nbsp; &nbsp;e.ScaleX = (float)scale;
 &nbsp; &nbsp; &nbsp; &nbsp;e.ScaleY = (float)scale;
 &nbsp;  }
}</code></pre><p>Scenes are meant as a better organization system for units of functionality in a game, and multiple can be loaded at once. Like Unity, you do set an "Active" scene (Dinghy calls it a "Target" scene) that designates where spawned entities are spawned into. Entity constructors <em>can</em> override this functionality and spawn entities into non-target scenes as well, but generally you probably want to set a target scene.</p><p>Scenes were one of those things that were conceptually easy to do based on all the previous work, so it was exciting to get to work on this because it felt like I was really reaping what I had sown (in a good way).</p><p>Getting Dear ImGui working was a bit harder because it meant threading the needle between Dear ImGui, Sokol, cimgui.h, and the Zig build pipeline. Specifically, it was weird because I was mixing C and C++ libs together in a target final DLL. What was nice to find was that the process was a bit simpler to do in the end than I thought it was, but at the same time Zig is still very much in development with pretty bad docs, so finding answers for questions I had was a matter of pestering the Zig Discord until I got the answer I was looking for. For reference, here's my <code>build.zig</code> file, with it largely being an edit of the <a href="https://github.com/floooh/sokol-zig/blob/master/build.zig">one Andres created for the Sokol Zig bindings</a>:</p><pre><code>const std = @import("std");
const builtin = @import("builtin");
const Builder = std.build.Builder;
const LibExeObjStep = std.build.LibExeObjStep;
const CrossTarget = std.zig.CrossTarget;
const Mode = std.builtin.Mode;
&#8203;
pub const Backend = enum {
 &nbsp;  auto, &nbsp; // Windows: D3D11, macOS/iOS: Metal, otherwise: GL
 &nbsp;  d3d11,
 &nbsp;  metal,
 &nbsp;  gl,
 &nbsp;  gles2,
 &nbsp;  gles3,
 &nbsp;  wgpu,
};
&#8203;
pub const Config = struct {
 &nbsp;  backend: Backend = .auto,
 &nbsp;  force_egl: bool = false,
&#8203;
 &nbsp;  enable_x11: bool = true,
 &nbsp;  enable_wayland: bool = false
};
&#8203;
pub fn build(b: *std.Build) void {
&#8203;
 &nbsp;  var config: Config = .{};
 &nbsp; &nbsp; &nbsp; &nbsp;
 &nbsp;  const force_gl = b.option(bool, "gl", "Force GL backend") orelse false;
 &nbsp;  config.backend = if (force_gl) .gl else .auto;
 &nbsp;  config.enable_wayland = b.option(bool, "wayland", "Compile with wayland-support (default: false)") orelse false;
 &nbsp;  config.enable_x11 = b.option(bool, "x11", "Compile with x11-support (default: true)") orelse true;
 &nbsp;  config.force_egl = b.option(bool, "egl", "Use EGL instead of GLX if possible (default: false)") orelse false;
&#8203;
 &nbsp;  const target = b.standardTargetOptions(.{});
 &nbsp;  const optimize = b.standardOptimizeOption(.{});
 &nbsp; &nbsp;
 &nbsp;  const cpp_sources = [_][]const u8 {
 &nbsp; &nbsp; &nbsp;  "imgui.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/cimgui.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/imgui/imgui.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/imgui/imgui_demo.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/imgui/imgui_draw.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/imgui/imgui_tables.cpp",
 &nbsp; &nbsp; &nbsp;  "../../cimgui/src/cimgui/imgui/imgui_widgets.cpp",
 &nbsp;  };
 &nbsp; &nbsp;
 &nbsp;  const c_sources = [_][]const u8 {
 &nbsp; &nbsp; &nbsp;  "sokol.c"
 &nbsp;  };
 &nbsp; &nbsp;
 &nbsp; &nbsp; const dll = b.addSharedLibrary(.{
 &nbsp; &nbsp; &nbsp;  .name = "sokol",
 &nbsp; &nbsp; &nbsp;  .target = target,
 &nbsp; &nbsp; &nbsp;  .optimize = optimize
 &nbsp;  });
 &nbsp;  dll.linkLibCpp();
 &nbsp;  dll.linkLibC();
 &nbsp; &nbsp;
 &nbsp;  var _backend = config.backend;
 &nbsp;  if (_backend == .auto) {
 &nbsp; &nbsp; &nbsp;  if (dll.target.isDarwin()) { _backend = .metal; }
 &nbsp; &nbsp; &nbsp;  else if (dll.target.isWindows()) { _backend = .d3d11; }
 &nbsp; &nbsp; &nbsp;  else { _backend = .gl; }
 &nbsp;  }
 &nbsp;  const backend_option = switch (_backend) {
 &nbsp; &nbsp; &nbsp;  .d3d11 =&gt; "-DSOKOL_D3D11",
 &nbsp; &nbsp; &nbsp;  .metal =&gt; "-DSOKOL_METAL",
 &nbsp; &nbsp; &nbsp;  .gl =&gt; "-DSOKOL_GLCORE33",
 &nbsp; &nbsp; &nbsp;  .gles2 =&gt; "-DSOKOL_GLES2",
 &nbsp; &nbsp; &nbsp;  .gles3 =&gt; "-DSOKOL_GLES3",
 &nbsp; &nbsp; &nbsp;  .wgpu =&gt; "-DSOKOL_WGPU",
 &nbsp; &nbsp; &nbsp;  else =&gt; unreachable,
 &nbsp;  };
&#8203;
 &nbsp;  if (dll.target.isDarwin()) {
 &nbsp; &nbsp; &nbsp;  inline for (c_sources) |csrc| {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.addCSourceFile(.{
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .file = .{ .path = csrc },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .flags = &amp;[_][]const u8{ "-ObjC", "-DIMPL", backend_option },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  });
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  inline for (cpp_sources) |csrc| {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.addCSourceFile(.{
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .file = .{ .path = csrc },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .flags = &amp;[_][]const u8{ "-ObjC++", "-DIMPL", backend_option },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  });
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  dll.linkFramework("Cocoa");
 &nbsp; &nbsp; &nbsp;  dll.linkFramework("QuartzCore");
 &nbsp; &nbsp; &nbsp;  dll.linkFramework("AudioToolbox");
 &nbsp; &nbsp; &nbsp;  if (.metal == _backend) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkFramework("MetalKit");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkFramework("Metal");
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  else {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkFramework("OpenGL");
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  } else {
 &nbsp; &nbsp; &nbsp;  var egl_flag = if (config.force_egl) "-DSOKOL_FORCE_EGL " else "";
 &nbsp; &nbsp; &nbsp;  var x11_flag = if (!config.enable_x11) "-DSOKOL_DISABLE_X11 " else "";
 &nbsp; &nbsp; &nbsp;  var wayland_flag = if (!config.enable_wayland) "-DSOKOL_DISABLE_WAYLAND" else "";
&#8203;
 &nbsp; &nbsp; &nbsp;  inline for (c_sources) |csrc| {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.addCSourceFile(.{
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .file = .{ .path = csrc },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .flags = &amp;[_][]const u8{ "-DIMPL", backend_option, egl_flag, x11_flag, wayland_flag },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  });
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  inline for (cpp_sources) |csrc| {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.addCSourceFile(.{
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .file = .{ .path = csrc },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .flags = &amp;[_][]const u8{ "-DIMPL", backend_option, egl_flag, x11_flag, wayland_flag },
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  });
 &nbsp; &nbsp; &nbsp;  }
&#8203;
 &nbsp; &nbsp; &nbsp;  if (dll.target.isLinux()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  var link_egl = config.force_egl or config.enable_wayland;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  var egl_ensured = (config.force_egl and config.enable_x11) or config.enable_wayland;
&#8203;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("asound");
&#8203;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (.gles2 == _backend) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("glesv2");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (!egl_ensured) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  @panic("GLES2 in Linux only available with Config.force_egl and/or Wayland");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  } else {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("GL");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (config.enable_x11) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("X11");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("Xi");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("Xcursor");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (config.enable_wayland) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("wayland-client");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("wayland-cursor");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("wayland-egl");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("xkbcommon");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (link_egl) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibrary("egl");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  else if (dll.target.isWindows()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("kernel32");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("user32");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("gdi32");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("ole32");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  if (.d3d11 == _backend) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("d3d11");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  dll.linkSystemLibraryName("dxgi");
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;
 &nbsp;  b.lib_dir = "../../../../Dinghy.Core/libs";
 &nbsp;  b.installArtifact(dll);
}</code></pre><p>On the actual library side, I ended up using the cimgui.h C bindings for the actual C# PInvoke code, which, as you can see above, is compiled alongside the normal C++ Dear ImGui library in the final DLL. I tried binding against the raw Dear ImGui headers, but ran into some issues with the PInvoke code for the C++ headers that were maybe solvable but I just opted for cimgui.h instead. Like everything else, the bindings are generated via <a href="https://github.com/dotnet/ClangSharp">ClangSharpPInvokeGenerator</a> for MAXIMAL SPEED.</p><p>Once the scene system and Dear ImGui were setup, I set about porting all the demos to the scene system and used some nice little bit of reflection (did you notice the attributes on the Demo code samples?) to procedurally build the UI to move between them. This means the overhead to add new demos is really low, which helps me maintain development velocity and not feel too much pressure about how hard it may be to add a new one. Here's the relevant code:</p><pre><code>ImGUIHelper.Wrappers.BeginMainMenuBar();
if (ImGUIHelper.Wrappers.BeginMenu("Dinghy")) {
 &nbsp;if (ImGUIHelper.Wrappers.BeginMenu("Demos")) {
 &nbsp; &nbsp;Scene? scene = null;
 &nbsp; &nbsp;foreach (var type in demoTypes) {
 &nbsp; &nbsp; &nbsp;if(ImGUIHelper.Wrappers.MenuItem(type.Name)) {
 &nbsp; &nbsp; &nbsp; &nbsp;scene = Util.CreateInstance(type.Type) as Scene;
 &nbsp; &nbsp; &nbsp; &nbsp;scene.Name = type.Name;
 &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;if (scene != null) {
 &nbsp; &nbsp; &nbsp;Engine.TargetScene.Unmount(() =&gt; {
 &nbsp; &nbsp; &nbsp; &nbsp;scene.Mount(0);
 &nbsp; &nbsp; &nbsp; &nbsp;scene.Load(scene.Start);
 &nbsp; &nbsp;  });
 &nbsp;  }
 &nbsp; &nbsp;ImGUIHelper.Wrappers.EndMenu();
  }
 &nbsp;ImGUIHelper.Wrappers.EndMenu();
}
ImGUIHelper.Wrappers.EndMainMenuBar();</code></pre><p>You can see a peek at some scene lifecycle management stuff here as well &#8212; Unmount has a callback you can tie into to do whatever else &#8212; in this case I mount a new scene and set it to Load, with a callback for the scene to start right after it loads.</p><p>You can also see some <code>ImGUIHelper.Wrapper</code> methods &#8212; working with raw PInvoke ImGui bindings is a bit onerous for end users (lots of <code>fixed</code> statements, etc.), so I'm working to wrap a lot of the functionality around managed function calls that at least get rid of boilerplate for ImGUI stuff and provide ways to pass strings to function calls without needing to explicitly call <code>fixed</code> in your own code. For example, <code>ImGUIHelper.Wrappers.BeginMenu("Dinghy")</code> wraps this way:</p><pre><code>public static unsafe bool BeginMenu(string name, bool enabled = true)
{
 &nbsp; &nbsp;var b = System.Text.Encoding.UTF8.GetBytes(name);
 &nbsp; &nbsp;fixed (byte* ptr = b)
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;return Internal.Sokol.ImGUI.igBeginMenu((sbyte*)ptr,(byte)(enabled ? 1 : 0)) &gt; 0;
 &nbsp;  }
}</code></pre><p>This way it's really easy to add in normal ImGUI calls wherever. For example (again), one thing I did that you may have seen in the particle demo is that I can use a similar reflection thing a la Unity to draw runtime property editors for any object:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FWCF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FWCF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 424w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 848w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FWCF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png" width="1456" height="1134" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1134,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128013,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FWCF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 424w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 848w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!FWCF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e815b3c-e3d0-4879-97f3-8e9b7b6acc72_1592x1240.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This code is all you need to do that:</p><pre><code>DrawEditGUIForObject("emitter",ref emitter);</code></pre><p>You can easily do this for any object or config anything. It's really nice! I suspect this function may be used a lot for Dinghy games so I'm working on fleshing it out a lot with nice defaults based on field types, and also providing ways for devs to author their own properties for editing (think Unity CustomPropertyDrawer but with ImGUI). I'll likely defer serialization to end-users as well, but proving a nice on-demand edit option for users is pretty nice (I think!).</p><p>A note on Magic: Dinghy's core pillars are still immediacy, coziness, and magic. Right now I think I'm doing a lot in the immediacy/coziness dimension, but the engine definitely lacks the Magic. I've got plans for implementing that stuff down the road, but for now the core functionality is still the target, and the Magic is something that would build on top of that foundation. As such, not a lot of magic right now!</p><p>Lastly, one thing I've been thinking a lot about is <a href="https://luau-lang.org/">Luau</a>. I <a href="https://github.com/afterschoolstudio/Luau.NET">spiked a prototype to get Luau working in C#</a>, and the more I think about it the more I think it would be really cool for most all of Dinghy's functionality to be exposed via Luau scripts. This would unlock things like live-coding at runtime, which, afaik, isn't a thing most engines offer. <a href="https://www.remedygames.com/article/how-northlight-makes-alan-wake-2-shine">I'm really inspired by what seems possible with Luau</a> (not to mention it being battle-tested by the Roblox team), and I like the idea that Dinghy could, with Luau support, be a stepping stone for Roblox players/creators looking to leave the Roblox ecosystem and do standalone development. Also, live-coding is <em>definitely</em> in line with the principle of "immediacy", so I'm really considering it. That said, the only work done so far is that prototype, but expect to hear more about Luau in Dinghy in the future.</p><div><hr></div><p>In all, I'm feeling really good where Dinghy is at. It's really meeting the exact goals I set out for it from the start, and I can feel how already I want to make stuff with it. If you're someone also interested, please reach out to me! I'd love to put together a small cohort of users to start getting a sense of how people like it/what they want/need. There are a ton of loose ends and missing functionality in the engine, but I think it's already at, if not VERY close to, having a lot of what you need to make a simple and small game to post somewhere like itch. If this is you, please reach out!</p><p>Otherwise, looking forward to sharing more progress in the next few months about where things are at and also hopefully share the first real game made with it!</p><p>Until next time!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Afterschool's Tools]]></title><description><![CDATA[A new newsletter section for people who want a peek behind the scenes]]></description><link>https://afterschool.studio/p/afterschools-tools</link><guid isPermaLink="false">https://afterschool.studio/p/afterschools-tools</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Mon, 09 Oct 2023 15:11:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!DM7T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Making games is hard, and one of the ways to stave off that ever-growing complexity is to develop tools to make working with things <em>easier</em>. Tools helped Cantata be the insane 30-hour tactics campaign it is made with a team of only a handful of people. Tools keep us on track, ship faster, iterate more quickly, etc.</p><p>At Afterschool, we&#8217;re committed to building out not only internal tools to help us develop games more quickly, but to also release some of those tools out into the wild to help grow the wider game development ecosystem.</p><p>To that end, we&#8217;re spinning up a new section of this newsletter, <strong>Tools</strong>, that tracks the progress and development of our tools and other R&amp;D efforts.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p><p>We&#8217;ve got two posts already available for reading:</p><div><hr></div><p>First, an overview of the C# game framework we&#8217;re working on, Dinghy:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e607d5cf-5e7a-4754-b0bc-6b524816e6e0&quot;,&quot;caption&quot;:&quot;Well hello again. Been a minute eh? Turns out making a whole videogame is a lot of work, so the amount of time I've been able to dedicate to any side projects had been somewhat minimal. Doing something as \&quot;big\&quot; as Dinghy is even harder to find time for, because there's so much initial exploration and so little return.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Dinghy 2023 Updates&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:3467437,&quot;name&quot;:&quot;Kyle Kukshtel&quot;,&quot;bio&quot;:&quot;lead dev + creative director at afterschool.studio. making cantata, something new, depot and dinghy.xyz. co-found of superculture.network and bad end podcast. previous co-founded volumetric capture company scatter.\n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a754f80b-d9a7-4126-bac3-41f74db16fa9_768x768.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-10-02T17:05:59.431Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://afterschool.studio/p/2023&quot;,&quot;section_name&quot;:&quot;Tools&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:137598272,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;The Afterschool Studio Newsletter&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3beb45a-631e-4a0a-9d93-56b291eaefad_277x277.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Next is the first alpha release of a skunkworks moodboarding tool we&#8217;re developing called Dreamwalker:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f30bc646-15d1-43b6-8312-a827dd80bb94&quot;,&quot;caption&quot;:&quot;I&#8217;ve been playing around with generative image models a lot since last year and one major thing that stuck out was that using them in general seemed to really de-emphasize &#8220;playfulness&#8221;. The tools then (and now) were really geared towards the idea of putting together &#8220;the perfect prompt&#8221; instead of just experimenting. Chat interfaces, prompt constructio&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Introducing Dreamwalker&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:3467437,&quot;name&quot;:&quot;Kyle Kukshtel&quot;,&quot;bio&quot;:&quot;lead dev + creative director at afterschool.studio. making cantata, something new, depot and dinghy.xyz. co-found of superculture.network and bad end podcast. previous co-founded volumetric capture company scatter.\n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a754f80b-d9a7-4126-bac3-41f74db16fa9_768x768.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-10-09T14:51:13.960Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://afterschool.studio/p/introducing-dreamwalker&quot;,&quot;section_name&quot;:&quot;Tools&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:137780797,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;The Afterschool Studio Newsletter&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3beb45a-631e-4a0a-9d93-56b291eaefad_277x277.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><p>In addition, we&#8217;ve got two <em>other</em> tools fully available now, <strong>both used throughout Cantata</strong>, that we have released publicly:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DM7T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DM7T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 424w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 848w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DM7T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png" width="1456" height="929" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:929,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!DM7T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 424w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 848w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!DM7T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed5ba6aa-22e1-4b03-a974-93085fa96aaa_3000x1914.png 1456w" sizes="100vw" loading="lazy" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Depot</h2><p><a href="https://depot-editor.com">https://depot-editor.com</a></p><p>Depot is a data editing tool designed for games that give you the ability to author rich interconnected data in a JSON format but edited like a spreadsheet. We used Depot extensively on Cantata and as such is the backbone of the game as well as its modding format, translation data, etc.</p><p>For games of any size, Depot is the tool for you.</p><p><a href="https://marketplace.visualstudio.com/items?itemName=afterschool.depot">Download for Visual Studio Code here</a> (<strong>11K downloads!</strong>)</p><h2>Squiggle</h2><p><a href="https://github.com/afterschoolstudio/squiggle">https://github.com/afterschoolstudio/squiggle</a></p><p>Squiggle is a very simple scripting language and runtime that allows you to author and execute sequential commands inside a game at runtime. We developed Squiggle as a lightweight alternative to tools like Ink or Yarn, such that we could author dialog and code-commands inside of Cantata without needing to perform a pre-compile step.</p><p>This is a simple Squiggle script:</p><pre><code><code>[playSound knock 1]
Carol: Hello! I've arrived!
Carol: And I've brought something special!
[playAnimation move carol door]
[setLights dim]</code></code></pre><div><hr></div><p>We&#8217;ve got a specific forum section for our tools where you can talk about them/test out new releases <a href="https://forums.afterschool.studio/c/tools/8">here</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://forums.afterschool.studio/c/tools/8" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dvR9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 424w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 848w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dvR9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png" width="1456" height="883" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:883,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:757336,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://forums.afterschool.studio/c/tools/8&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dvR9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 424w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 848w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!dvR9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93179edf-d365-4579-a3c7-cb3306e20578_2790x1692.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We&#8217;ve got a few other things in the pipe as well that we&#8217;ll be happy to talk about in the future, but just wanted to generally share everything we&#8217;ve been up to both in and around game development and hopefully inspire people to make their own tools, and give ours a try!</p><p>Lastly, this email was sent out as part of the &#8220;Tools&#8221; section of the Afterschool newsletter. We&#8217;ve gone ahead and added everyone to the newsletter by default to get the word out, but if you don&#8217;t want news/updates on our tools, you can unsubscribe to <em>just this section </em>of the newsletter by managing your subscription in Substack.</p><p>However if you&#8217;re new to us or want more, feel free to subscribe! Thanks for reading and talk again soon!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Introducing Dreamwalker]]></title><description><![CDATA[First alpha release]]></description><link>https://afterschool.studio/p/introducing-dreamwalker</link><guid isPermaLink="false">https://afterschool.studio/p/introducing-dreamwalker</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Mon, 09 Oct 2023 14:51:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!A6rx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A6rx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A6rx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 424w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 848w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A6rx!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg" width="1200" height="707.1428571428571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:858,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:720793,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!A6rx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 424w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 848w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!A6rx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fe7bfbd-5d36-48a0-bacb-8e76c68d4f50_2912x1716.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>I&#8217;ve been playing around with generative image models a lot since last year and one major thing that stuck out was that using them in general seemed to really de-emphasize &#8220;playfulness&#8221;. The tools then (and now) were really geared towards the idea of putting together &#8220;the perfect prompt&#8221; instead of just experimenting. Chat interfaces, prompt construction, etc. all seem ill-suited for the work of &#8220;finding the image you&#8217;re looking for&#8221;.</p><p>I&#8217;d had an idea in my head for a while around trying to make this experience better, and when the first AIxUX was announced in NYC I thought I&#8217;d throw my hat in the ring and hack on something to see what could come of it. And I did it! Here&#8217;s my presentation from that event (timestamped):</p><div id="youtube2-76chBva31Iw" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;76chBva31Iw&quot;,&quot;startTime&quot;:&quot;1735s&quot;,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/76chBva31Iw?start=1735s&amp;rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>I called it &#8220;Dreamwalker&#8221; &#8212; a way to explore latent space. <a href="https://dreamwalker.ai">I also got the domain</a>. The idea was to make working with image generations more like developing, or even <em>tending </em>to something like a moodboard. Have it be this <em>corpus </em>of exploration that sees you searching for ideas and pruning branches and trying to hone in on what you&#8217;re thinking.</p><p>The idea is that Dreamwalker gets you from that blank page feeling and maybe does help you find a good prompt, but helps you mostly just get started. The images it generates can be starting points, helpful to find that next step.</p><p>After the presentation, Dreamwalker sat on my harddrive for a bit. I thought about what I wanted to do with it and all the dreams I had for things it could do, but instead of trying to do all of it I have just (ROUGHLY) buttoned up the core features of the tool and am happy to finally release it to the world today to see what people think. Here&#8217;s a video demonstrating the core functionality of the tool:</p><div id="youtube2-k_mJgFmdWWY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;k_mJgFmdWWY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/k_mJgFmdWWY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>I think in part, seeing what OpenAI is doing with DALL-E chat prompt work makes me want to also get a stake in the ground for the way I think things should go. I want people to be able to think outside the chat prompt for image model interaction, and hopefully I can inspire some other people to also create non-traditional AI tools.</p><p>You can download Dreamwalker via the link below, and also find some instructions on how to use it:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://forums.afterschool.studio/t/dreamwalker-alpha-2-release/66&quot;,&quot;text&quot;:&quot;Download Dreamwalker Here&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://forums.afterschool.studio/t/dreamwalker-alpha-2-release/66"><span>Download Dreamwalker Here</span></a></p><p>The link is a forum link, so if you have thoughts or ideas or comments, feel free to leave them there! I&#8217;d love to know what people think and what they find useful/features they would like to see.</p><p>Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Dinghy 2023 Updates]]></title><description><![CDATA[News and updates from 2023, including a preliminary pre-alpha]]></description><link>https://afterschool.studio/p/2023</link><guid isPermaLink="false">https://afterschool.studio/p/2023</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Mon, 02 Oct 2023 17:05:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Well hello again. Been a minute eh?</p><p>Turns out making <a href="https://store.steampowered.com/app/690370/Cantata/">a whole videogame</a> is a lot of work, so the amount of time I've been able to dedicate to <em>any</em> side projects had been somewhat minimal. Doing something as "big" as Dinghy is even harder to find time for, because there's so much initial exploration and so little return.</p><p>There HAS been work though, especially since Cantata's release, so here's something I'm happy to show:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yU9X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yU9X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 424w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 848w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 1272w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yU9X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif" width="984" height="549" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:549,&quot;width&quot;:984,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:397294,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yU9X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 424w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 848w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 1272w, https://substackcdn.com/image/fetch/$s_!yU9X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab42bdf7-c091-4fa1-bb54-beca04b647a7_984x549.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>I'll talk about this more in a little bit, but first wanted to talk a little bit about <em>thinking</em> instead of just coding.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p><p>Something that working on Cantata forced me to do, just given time contention, was that the time I could spend on Dinghy was never enough to really start <em>coding</em> it. So instead, I spent a lot of time <em>thinking</em> about it, channeling <a href="https://www.youtube.com/watch?v=f84n5oFoZBc">Rich Hickey's idea of "Hammock Driven Development"</a>. I have a lot of project ideas, but not a lot of time, so my strategy for focusing on something/choosing something to actually pursue is to, almost like spaced repetition, return to ideas over time to see if they "stick". If they don't stick, I'll stop letting it take up mind space, and if so, I'll think a little more about it. I write down nearly every idea I have with this in mind, knowing that 90% of them will fade beyond that initial spark, but some will indeed rise to the top. I continuously circle around the ideas and try to re-surface them to myself often enough that I can reevaluate if I still like the idea, and if so, think more about it.</p><p>Keeping this running catalog of ideas is especially important during the throes of another project. Big projects take up all of your time, but then can all at once stop, and then that vacuum of newfound free time can easily absorb even the most ill-advised idea that may have just happened to pop into your head around the same time. What you want is that when you free up, you start working on the <em>right</em> next choice. And after many rounds of thinking over it and it continuing to stick, <em>Dinghy</em> is definitely one of those things.</p><p>Dinghy consistently passes that test of "stickiness", and over time feels like what it's trying to do is more than just convenient but instead, <a href="https://www.theverge.com/2023/9/22/23882768/unity-new-pricing-model-update">vital</a>. An exodus of C# programmers from Unity, especially people that do 2D, are looking around and trying to find what makes sense to go to next, and there honestly aren't enough good answers. Dinghy is trying to be one of them. It's meant to be a simple, cross platform framework for C# that you can rapidly prototype games and interactive things in, but also have bones that can scale to larger projects. Seems simple enough, and all the pieces are really laying there, but nobody else has done it!</p><p>I think also really just sticking to 2D and never trying to touch 3D is really helping me maintain that focus. If you assume 2D, you can do a lot of stuff around engine/API UX that wouldn't make sense for a 3D engine, but also would make there be a lot of "API noise" for people doing 2D things in an engine that supports 3D. So we're keeping it trim and to the point.</p><p>So <em>what</em> has actually happened? Well, a lot!</p><h2><strong>Sokol</strong></h2><p>Probably the biggest change from the previous blog posts and is that I moved from Kinc to <a href="https://github.com/floooh/sokol">Sokol</a>. There are a few reasons for this:</p><ul><li><p>Sokol is generally further along than Kinc and feels less like a prototype.</p></li><li><p>The primary maintainer of the Sokol repo is really friendly and responsive.</p></li><li><p>More people in general know about Sokol and use it. For someone like me that knows so little, being able to ask about Sokol to other people besides the repo owner is really nice.</p></li><li><p>Sokol has <em>tons</em> of examples, making learning the headers a lot easier! The documentation is also embedded in the source itself, which is weird at first but then turns out to be really nice &#8212; you just search what you are looking for in the IDE and can instantly pull up the docs about it.</p></li><li><p>Sokol has lots of built in support for other libs (DearImGUI, etc.) that are mostly drop-in.</p></li></ul><p>Related to that last point, Sokol has a lot of nice little things that really help out engine dev. The DearImGUI bindings are obviously big, but then other nice examples like the <a href="https://floooh.github.io/sokol-html5/fontstash-sapp.html">Fontstash</a> interop, <a href="https://floooh.github.io/sokol-html5/debugtext-sapp.html">Debug Text</a>, and upcoming WebGPU bindings, make me feel good about "living" in the Sokol ecosystem.</p><p><strong>Sokol_GP</strong></p><p>As a small aside, I'm also primarily using <a href="https://github.com/edubart/sokol_gp">Sokol_GP</a> for the actual 2D drawing &#8212; it's basically a simple modern 2D drawing lib that sits on top of Sokol mostly with ease of use. You can mix and match Sokol's core libs with GP, so it's been pretty nice!</p><h2><strong>ClangSharpPInvokeGenerator</strong></h2><p>I've also moved to using the <a href="https://github.com/dotnet/ClangSharp">ClangSharpPInvokeGenerator</a> to generate the PInvoke code to bind C# to Sokol and other libs. In the past I was mostly handwriting all the PInvoke code. This was... insightful, but incredibly tedious and really prone to error. It was nice to get my head around the whole Marshalling/PInvoke workflow, but one thing you realize in doing that is that there <em>is</em> a right answer to any binding function, and as such generating them is far more efficient. I also learned more about the concept of "blittable" bindings (aka, no runtime Marshaling), which pushed me to adopt the new generator because it directly spits out those bindings!</p><p>Working with blittable bindings is great for performance, but it does mean the API surface of using those functions is a bit more involved. Starting up Sokol for example looks like this:</p><pre><code><code>unsafe
{
    var window_title = System.Text.Encoding.UTF8.GetBytes(opts.appName);
    fixed (byte* ptr = window_title)
    {
        //init
        sapp_desc desc = default;
        desc.width = opts.width;
        desc.height = opts.height;
        desc.icon.sokol_default = 1;
        desc.window_title = (sbyte*)ptr;
        desc.init_cb = &amp;Initialize;
        desc.event_cb = &amp;Event;
        desc.frame_cb = &amp;Frame;
        desc.cleanup_cb = &amp;Cleanup;
        desc.logger.func = &amp;Sokol_Logger;
        App.run(&amp;desc);
    }
}
</code></code></pre><p>Pointers? Fixed?? Address references??? Doing it this way does mean you've got to dive headfirst into <code>unsafe</code> waters, which (for me at least) meant a large onboarding period of just wrapping my head around this "type" of C# programming. But now that I'm on the other side of that cost, <a href="https://blog.kylekukshtel.com/csharp-lowlevel-memory-pinvoke-span-blittable-bindings">I'm much more comfortable with it</a>! C# can also nicely encapsulate this work, so for anyone who uses Dinghy they don't need to worry about any of it. Working in Dinghy is more "normal" C#.</p><p>As a side note, I think I may write a small post on <a href="https://blog.kylekukshtel.com/">my main blog</a> about using the generator. The docs are a bit hard to parse so I think it could be useful to see a common use case in action.</p><h2><strong>Zig Build</strong></h2><p>So I've got nice new bindings for Sokol, but how about actually compiling the headers?</p><p>Previously, the build system was a bit weird. But weird in a way that I imagine any cross-platform library is. Building the headers meant generating platform-specific project files for the dependent platform (Visual Studio/MSVC on Windows, XCode on OSX), then basically building those projects from the command line version of those tools. This seemed sort of inescapable, and I guess is nice for some use cases, but I always found it sort of jank.</p><p>But then I learned about Zig, and more specifically that Zig ships with a drop-in, cross-platform C compiler replacement. I tried it... and it works?? It feels like magic. So now all I basically do is just run zig build (with the correct Zig script) and out comes platform-specific DLLs.</p><p>I'm also lucky here because Sokol has actively maintained and auto-generated Zig bindings, and also happens to have a <a href="https://github.com/floooh/sokol-zig/blob/master/build.zig">Zig Build script</a> that I can copy and modify to build a DLL instead of an exe. Thanks Andres!</p><p>Worth saying as well that I am generally digging Zig. Dinghy is still very much focused to be a C# library, but I can definitely see myself <a href="https://github.com/floooh/pacman.zig/blob/main/src/pacman.zig">dipping into Zig + Sokol land on the side</a>.</p><p><strong>General Lib Workflow</strong></p><p>This pipeline also really works for other <a href="https://github.com/nothings/stb">STB</a> style libs, so I've started to incorporate some STB headers in as well. stb_image specifically is now in the engine for image loading, and I'm eyeing others in there as things grow out. I feel like with STB and other <a href="https://github.com/nothings/single_file_libs">single-file header</a> libs (like <a href="https://github.com/RandyGaul/cute_headers">the Cute ones</a>), I'll have most core functionality I'll need at the C level and all the wrangling of libs themselves at the C# level.</p><h2><strong>ECS</strong></h2><p>Everyone's favorite game development buzzword. I'm making Dinghy be an ECS-oriented engine (via <a href="https://github.com/genaray/Arch">Arch</a>). If I'm honest I'm just trying this on a bit. I'm not fully committed to it yet but so far it's a nice paradigm and it <em>is</em> fast. I think people discount how many objects are often in 2D games compared to 3D games, so it does feel like gaining performance from this paradigm makes sense.</p><p>You <em>can</em> circumvent the ECS (or everything?) in the engine if you want, but I intend to make all the learning material/tutorials/etc. try to repeat and show the same paradigms. The "critical path" of the engine should feel well-trodden and <em>smooth</em>.</p><p>One thing I do like about Arch is that, in addition to just the general quality of the library itself, it has some Dinghy-aligned features (specifically "magic") that I think will be nice to have via it's Extensions package and the source-generated Queries (aka systems):</p><pre><code><code>[Query]
[All&lt;Player, Mob&gt;, Any&lt;Idle, Moving&gt;, None&lt;Alive&gt;]  // Attributes also accept non generics 
public void ResetVelocity(ref Velocity vel)
{
    vel = new Velocity{ X = 0, Y = 0 };
}
</code></code></pre><p>The actual query code is source-generated against that function + attributes, and reduces the overall need for boilerplate.</p><h2><strong>Actual Engine Screenshot</strong></h2><p>So let's talk about what we're seeing here (It runs smooth I promise, just GIF recording, etc. etc.):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uwVt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uwVt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 424w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 848w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 1272w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uwVt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif" width="984" height="549" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:549,&quot;width&quot;:984,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:397294,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uwVt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 424w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 848w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 1272w, https://substackcdn.com/image/fetch/$s_!uwVt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86da026c-7ee5-4796-8ea6-bcad88768014_984x549.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Hell yeah! So at a baseline, the key thing is that, <strong>all you need to get what you see on the left is </strong><em><strong>just</strong></em><strong> the code on the right</strong> (provided you have the Engine DLLS obv, etc. etc.) No platform setup code, no <code>GraphicsDevice</code> to worry about &#8212; You just write the code on the right, and you can do what's on the left. Ideally we can make it even more terse, but for now you get the idea. The code is basically <em>all signal</em> with minimal (no?) boilerplate.</p><p>What's especially cool about this is that, a few years ago, I wrote fake Dinghy code to show how I wanted game authoring to be, and this basically meets that target. It's also not like it's sitting on a ton of abstractions just to prove a point &#8212; this is all workhorse code that you would probably write the same if it's for your project.</p><h3><strong>Low "Ceremony"</strong></h3><p>Jon Skeet (blessed be he), has this concept of "ceremony" in programming. The idea of it is sort of ancillary noise that has to exist next to code that actually <em>does something</em>, such that the "ceremonial" code isn't doing much besides scaffolding the core idea. So the idea is that ideally you can reduce how much ceremony which is required at a baseline, but, when you want to roll out the red carpet, you <em>can</em> still bring it back.It's the difference between old C# style "high-ceremony" main function entry:</p><pre><code><code>public class Program {
&#9;public static void Main(string[] args) {
&#9;&#9;Console.WriteLine("Hello World")
  }
}
</code></code></pre><p>And the "low ceremony" new style top-level statement entry:</p><pre><code><code>Console.WriteLine("Hello World"); //literally all you need in a Program.cs file
</code></code></pre><p>You <em>can</em> still do it the old way, but all the code is basically boilerplate and is the same for 99% of use cases, so instead of requiring ceremony, you can just <em>do</em> the thing you intend. Default instead to a common base case, with opportunity to expand into full ceremony if necessary.</p><p><strong>Dinghy.Quick</strong></p><p>Dinghy is very much crafted in this mold, and to that end is the <code>Dinghy.Quick</code> namespace, which this the code above uses. It's "you'll most likely do it <em>this</em> way" style functions and wrappers that are meant for quickly scaffolding games, and gets at that Dinghy tenet of "Immediacy" (with a dash of "cozy"). It takes barely two lines of code to get a sprite on screen, and nothing about the function constructors or method calls are ambiguous about what they output is.</p><p>You <em>can</em> use all the Engine APIs yourself (and you will for any large project), but the idea is to onboard new people really easily with the most likely versions of functions and data that they will use, and you can change it up when you outgrow them.</p><p>So instead of writing:</p><pre><code><code>InputSystem.Events.Key.Down += (key) =&gt;...
</code></code></pre><p>You can write:</p><pre><code><code>OnKeyDown += (key) =&gt;...
</code></code></pre><h3><strong>Workflow</strong></h3><p>Similarly, one of the key things I've been working on here was to really understand the development loop for Dinghy, and asking myself what does it mean to work <em>with</em> it.</p><p>I think this is related to a thread drawn from Dinghy's idea of "magic", but the more I think about games the more I really just end up thinking about "how can we make working with Data better?"</p><blockquote><p>Show me your code and conceal your data structures, and I shall continue to be mystified. Show me your data structures, and I won&#8217;t usually need your code. &#8211; Eric Raymond</p></blockquote><p>Game programming (and generally working with game engines) is so wrapped up in thinking about <em>code</em> that I want to try to frame (to users) that working with Dinghy is less about <em>writing code</em> and more about just <em>hooking up data</em>. Yes, there will be still be scripts and whatever, but thinking about, and getting users to think about, data from the <em>very</em> start of the project will I think be something really useful.</p><p>It's related to the idea that good data and dumb code is almost always better than bad data and good code. Dinghy wants to try and always give you Good Data, so that hooking it up for games is trivial. Going back to the idea of ceremony, it means looking at data as something that can be <em>directly actionable</em> instead of needing to wrap it in boilerplate.</p><p>There's the murmurings of an asset pipeline in the engine now (but also where a large focus of the "magic" I want to be is at), but the gist in terms of the current implementation is that external assets are wrapped up into data containers, and those data containers then have the ability to instantiate the most likely version of themselves into the world.</p><p>Dinghy will provide a lot of the common 2D ones out of the box (Textures, Sprites, Tilemaps, Animations, etc.), but you also easily author your own and tie those into the "import" pipeline. You can also easily compose data structures together (they're just classes) so if you need larger composite structures you can build those out as well.</p><blockquote><p>As an aside, I just wanted to mention how this is different from things like Unity out of the box. In Unity, you import an asset. That asset is <em>just</em> an asset and can be theoretically used for anything. In Dinghy, we assume that all data is instead <em>actionable</em> via it's own definition of an asset. Once an asset is in Unity, it's just loose sitting around, and then is attached to a component. That component can be on literally <em>any</em> type of object, that can then also contain literally <em>any</em> other components. On one hand, it's very flexible, but on the other hand it's very prone to <a href="https://en.wiktionary.org/wiki/footgun">foot-gunning</a> and misconfiguration, as there are basically no guardrails towards doing what is <em>likely intended</em>. Dinghy instead is meant to be more rigid, and provide you with <em>guardrails geared towards productivity</em>, with the ability to move outside them if you want to.</p></blockquote><p><strong>Data -&gt; Entity</strong></p><p>So for a simple example, we've got SpriteData, which takes in a reference texture name and some data about where the sprite should go on screen, great. Here's SpriteData currently:</p><pre><code><code>public record SpriteData(string texture,int startX = 0, int startY = 0) 
  : EntityData {
    public override void GetEntity(out Entity e)
    {
        e = Engine.World.Create(
            new Position(startX, startY), 
            new SpriteRenderer(texture));
    }
}
</code></code></pre><p>Notice that Data is a <code>record</code>, meaning that the class is meant to be immutable. It's just a container for information. However, by being data you have to define some notion of what it means to consume you. If you're a SpriteData, that means you're probably making a Sprite, and as such there is a direct function implemented to do just that.</p><p>You can still have non-object data, but the goal is to have no "loose" stuff lying around &#8212; everything should be data build towards entities, <em>or</em> data that gets directly incorporated into the development experience via [magic] code, but more on that in a future post.</p><p><strong>Entity -&gt; Components</strong></p><p>Once you've got an entity, you add some components to it to give it behavior. SpriteData's Entity gives you a Position and SpriteRenderer by default, but you can also add components after the fact (<a href="https://github.com/genaray/Arch/wiki/Performance-Features#bulk-adding">Arch has a few ways to do this</a>):</p><pre><code><code>SpriteData logo_img = new("logo.png");
var logo = Add(logo_img); //adding the logo to the scene
logo.Add(new Velocity()); //adding a velocity component
</code></code></pre><p>In addition to components, you <em>can</em> also do non-component behavior modification to the entity as well, so you <em>can</em> use the ECS to-taste:</p><pre><code><code>OnKeyDown += (key) =&gt;  {
&#9;ref var vel = ref logo.Get&lt;Velocity&gt;(); //arch's way to grab component data
&#9;(int dx, int dy) v = key switch {
&#9;&#9;Key.LEFT =&gt; (-1, 0),
&#9;&#9;Key.RIGHT =&gt; (1, 0),
&#9;&#9;Key.UP =&gt; (0, -1),
&#9;&#9;Key.DOWN =&gt; (0, 1),
&#9;&#9;_ =&gt; (0, 0)
&#9;};
&#9;vel.x += v.dx;
&#9;vel.y += v.dy;
};
</code></code></pre><p>If I was building this out as a real demo, I'd move that movement update code into its own PlayerMovementSystem class, and add in a PlayerControl component. But also if you're just throwing something together, you aren't beholden to just ECS. For really simple demos I could see also just not really emphasizing ECS, but then for more advanced ones showing how to work with it. Speaking of ECS...</p><p><strong>Components -&gt; Systems</strong></p><p>This is probably the main area Arch comes in, and leverages a nice querying/filtering API to act on Entities with the correct components in a (basically) non-allocated way:</p><pre><code><code>var query = new QueryDescription().WithAll&lt;Position,SpriteRenderer&gt;();
Engine.World.Query(in query, (in Entity e, ref SpriteRenderer r, ref Position p) =&gt; {
  //act on entites that match the query
}
</code></code></pre><p>For Dinghy, queries are simple classes that wrap Arch queries. They are registered with the engine internals and execute based on the Interface they implement:</p><pre><code><code>public abstract class RenderSystem : DSystem, IUpdateSystem {
    public void Update() {
        Render();
    }
    protected abstract void Render();
}

public class SpriteRenderSystem : RenderSystem {
    QueryDescription query = new QueryDescription().WithAll&lt;Position,SpriteRenderer&gt;();
    protected override void Render() {
        Engine.World.Query(in query, (in Entity e, ref SpriteRenderer r, ref Position p) =&gt; {
            //render code
        }
    }
}
</code></code></pre><p>Right now there is just IPreUpdate/IUpdate/IPostUpdate, but I may add more.</p><p>If you want to make a custom system in Dinghy, you just extend the base system and then add the interface in order to hook into standard system ticks.</p><p><strong>Performance</strong></p><p>I ran a na&#239;ve BunnyMark test and this current configuration gets me 50,000 entities all updating at 60fps. Not bad! There are lots of ways to make it faster, but it's nice to know that if you aren't thinking about performance at all you can get a pretty nice baseline without minimal setup.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p><h2><strong>Wrap</strong></h2><p>In general, I'm really happy with where Dinghy is at and where it's going. I feel like I could honestly start giving it out to some people soon if they're interested in giving it a spin and giving me some early feedback.</p><p>If you think this is you, feel free to respond to this email! Would happy to know what you're looking for and what you want to try and make. If you aren't getting this through email, you can email me at kyle@afterschool.studio and say you're interested in trying it out!</p><p>Otherwise, hoping to have at least one more update post by the end of the year, but until then thanks for reading and being part of the ride. Talk soon!</p>]]></content:encoded></item><item><title><![CDATA[New Cantata Tutorial Video]]></title><description><![CDATA[A new tutorial video to help the perplexed and a feature voting portal to help guide the upcoming development work.]]></description><link>https://afterschool.studio/p/cantata-tutorial-video-feature-voting</link><guid isPermaLink="false">https://afterschool.studio/p/cantata-tutorial-video-feature-voting</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Thu, 07 Sep 2023 20:06:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5xpB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5xpB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5xpB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 424w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 848w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5xpB!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:13659960,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5xpB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 424w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 848w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!5xpB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d1a5538-0e74-4b41-ba7f-7b31ddbffe11_3840x2160.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Hello all!</p><p><strong>WHEW!</strong></p><p>Cantata has fully made its way into the world and I couldn&#8217;t be happier with how it&#8217;s been received. To be clear, it is definitely a strange game and some people have bounced off it for that, but for every person that doesn&#8217;t find it to taste there are people that are pouring hours into the game and really engaging with what we&#8217;re trying to do.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;text&quot;:&quot;Purchase Cantata on Steam &#8599;&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://store.steampowered.com/app/690370/Cantata/"><span>Purchase Cantata on Steam &#8599;</span></a></p><p>For the unconvinced (and the confused) though, we&#8217;ve put together a How-To video to help visually walk people through what it actually means to play Cantata. If you don&#8217;t want to play the in-game tutorial or just want to check out what playing Cantata actually &#8220;is&#8221; before buying, I highly recommend you watch the video. It&#8217;s not an annotated play through of the tutorial, but instead a visual walkthrough of all the parts of the game with examples, highlighting, etc.</p><p>Check it out here:</p><div id="youtube2-S-NIddiv720" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;S-NIddiv720&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/S-NIddiv720?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><p>As we move beyond the 1.0 release of Cantata, I&#8217;m also starting to chart a path for what development looks like for the game. The Campaign of the game is finished, and as I look down the road there&#8217;s a fair number of quality of life enhancements for the game possible as well as focusing on heavily-requested items like a proper Skirmish AI.</p><p>Given that the development team is now just me, I&#8217;m unable to just work on everything at once, as much as I&#8217;d like to! So what I&#8217;ve done is introduce a feature voting portal on our forums where people can vote (and comment) on what specifically they would like to see next in the game:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://forums.afterschool.studio/c/cantata/feature-voting/13&quot;,&quot;text&quot;:&quot;Access Feature Voting &#8599;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://forums.afterschool.studio/c/cantata/feature-voting/13"><span>Access Feature Voting &#8599;</span></a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://forums.afterschool.studio/c/cantata/feature-voting/13" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HcME!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 424w, https://substackcdn.com/image/fetch/$s_!HcME!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 848w, https://substackcdn.com/image/fetch/$s_!HcME!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 1272w, https://substackcdn.com/image/fetch/$s_!HcME!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HcME!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png" width="1200" height="719.5054945054945" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:873,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:745528,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://forums.afterschool.studio/c/cantata/feature-voting/13&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HcME!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 424w, https://substackcdn.com/image/fetch/$s_!HcME!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 848w, https://substackcdn.com/image/fetch/$s_!HcME!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 1272w, https://substackcdn.com/image/fetch/$s_!HcME!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0128fd9e-ca36-458f-a9f3-bf9693af7d0a_2862x1716.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>On the page, once you register, you can vote for two options in the category. Once the category is closed, you will get any votes you put towards that category back and can reallocate them! My hope is that this helps everyone who plays and is interested in the ongoing work of Cantata feel empowered to help steer development towards what they would like to see in the game.</p><div><hr></div><p>Lastly, if you&#8217;re playing Cantata and enjoying it, please leave us a review on Steam! Every little bit helps as we&#8217;re still small a relatively low-profile game!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;text&quot;:&quot;Cantata on Steam &#8599;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://store.steampowered.com/app/690370/Cantata/"><span>Cantata on Steam &#8599;</span></a></p><p>Beyond that, we&#8217;ve still got more things cooking around Cantata. I want to make the game great and think we&#8217;ve got all the ingredients here to build something special on top of a solid foundation. Until next time, thanks so much for reading and following us along this journey. Enjoy your time on Shoal, discover its mysteries, and we&#8217;ll talk again soon!</p>]]></content:encoded></item><item><title><![CDATA[Cantata 1.0 Released!]]></title><description><![CDATA[We're out of Early Access and moving into to a post-1.0 world!]]></description><link>https://afterschool.studio/p/cantata-released</link><guid isPermaLink="false">https://afterschool.studio/p/cantata-released</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Tue, 15 Aug 2023 15:24:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cef33442-1528-437b-927f-433ce3b46b74_1500x1071.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://store.steampowered.com/app/690370/Cantata/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C7qP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 424w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 848w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 1272w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C7qP!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:1774396,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C7qP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 424w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 848w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 1272w, https://substackcdn.com/image/fetch/$s_!C7qP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e15f286-6cae-4aeb-afc9-1c17adb99268_4096x2304.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A journey that <a href="https://isotacticsdev.tumblr.com">started nearly a decade ago</a> is finally coming to a close as today <strong><a href="https://store.steampowered.com/app/690370/Cantata/">Cantata is officially released into 1.0 on Steam</a></strong>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;text&quot;:&quot;Purchase Cantata on Steam &#8599;&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://store.steampowered.com/app/690370/Cantata/"><span>Purchase Cantata on Steam &#8599;</span></a></p><p>To all of you that have been with us since the very beginning, thank you. The belief people held early on that this was a game worth playing and the comments and feedback given to the game from that point up until now have not only helped me continue what has turned out to be an incredibly ambitious and admittedly <em>weird </em>game, but have helped to better shape what the game actually is.</p><div id="youtube2-oyebI2x8Gqo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;oyebI2x8Gqo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/oyebI2x8Gqo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>As you can likely see from this email as well, we&#8217;ve changed newsletter provider and are now on Substack! The newsletter itself has been rebranded as The Afterschool Studio Newsletter to better reflect that this is not only the gathering point for Cantata, but a place for us to track the ongoing development around other projects (some exciting <strong>NEW </strong>things that are as of yet unannounced).</p><p>We&#8217;re also happy to announce that today marks the release of <a href="https://store.steampowered.com/app/690370/Cantata/">the Dreamwalker edition of Cantata</a>!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://store.steampowered.com/app/690370/Cantata/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JgH8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JgH8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Image" title="Image" srcset="https://substackcdn.com/image/fetch/$s_!JgH8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JgH8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7595f2-485b-4abf-8185-9bfbea0d1430_1200x675.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In addition to the game itself, the Dreamwalker edition contains an absolutely MASSIVE soundtrack for the game:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://store.steampowered.com/app/690370/Cantata/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z_RT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z_RT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Z_RT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!Z_RT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d295576-cc52-4c48-b539-bd1e4e133612_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Cantata&#8217;s composer, Royal Teague, went all out for this, and we&#8217;re so happy to offer a way for the music to be listened to outside the scope of the game itself. This thing also <em>goes </em>as well, and is full of music that totally stands up on its own while also conveying the texture of the game it&#8217;s pulled from. It&#8217;s that <em>good </em>listening, if you know what I&#8217;m saying. We even snuck a few tracks on here that aren&#8217;t even in the game! We can&#8217;t help ourselves!</p><p>With all that said, I again want to thank everyone that&#8217;s been on this journey with us since the alpha launched all those years ago. I&#8217;ve personally learned a ton about game development and design (and business!) in those years, and for all that stuck through until now, thanks for believing in me and thanks for believing in Cantata.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://store.steampowered.com/app/690370/Cantata/&quot;,&quot;text&quot;:&quot;Purchase Cantata on Steam &#8599;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://store.steampowered.com/app/690370/Cantata/"><span>Purchase Cantata on Steam &#8599;</span></a></p><p>(If you purchase and play, please leave us a positive review! It seriously helps the game standout on Steam&#8217;s backend and will help it find more players!)</p><div><hr></div><p>As Cantata crests out of Early Access and into 1.0, we&#8217;re obviously thinking about the future of the game and what it will hold. We&#8217;ve got some really interesting ideas in the pipe that we&#8217;ll be relying on the community again to help us navigate, so if this sounds interesting to you, definitely subscribe below to be notified when that (and some other things around <strong>REDACTED</strong>) are announced!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p><p></p><p>Thanks so much for reading and following us along this journey. For now, enjoy your time on Shoal, discover its mysteries, and we&#8217;ll talk again soon!</p>]]></content:encoded></item><item><title><![CDATA[Coming Soon]]></title><description><![CDATA[The New and Improved Afterschool Studio Newsletter]]></description><link>https://afterschool.studio/p/coming-soon</link><guid isPermaLink="false">https://afterschool.studio/p/coming-soon</guid><dc:creator><![CDATA[Kyle Kukshtel]]></dc:creator><pubDate>Fri, 07 Jul 2023 14:45:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iobI!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3beb45a-631e-4a0a-9d93-56b291eaefad_277x277.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is the <strong>Afterschool Studio</strong> newsletter, a newsletter with updates on the strategic videogame Cantata as well as news and thoughts about other projects and ideas we&#8217;re cooking.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://afterschool.studio/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://afterschool.studio/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>