<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ForceSensitiveSaiyan</title>
    <description>The latest articles on DEV Community by ForceSensitiveSaiyan (@forcesensitivesaiyan).</description>
    <link>https://dev.to/forcesensitivesaiyan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3986237%2F1416092f-a847-41b8-bd1e-2bea7b055d1d.jpeg</url>
      <title>DEV Community: ForceSensitiveSaiyan</title>
      <link>https://dev.to/forcesensitivesaiyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/forcesensitivesaiyan"/>
    <language>en</language>
    <item>
      <title>I built a game with zero asset files - everything is generated in code</title>
      <dc:creator>ForceSensitiveSaiyan</dc:creator>
      <pubDate>Mon, 15 Jun 2026 21:18:07 +0000</pubDate>
      <link>https://dev.to/forcesensitivesaiyan/i-built-a-game-with-zero-asset-files-everything-is-generated-in-code-48ae</link>
      <guid>https://dev.to/forcesensitivesaiyan/i-built-a-game-with-zero-asset-files-everything-is-generated-in-code-48ae</guid>
      <description>&lt;h1&gt;
  
  
  Building a Game with Zero Assets in Godot
&lt;/h1&gt;

&lt;p&gt;This is the first game I've ever made.&lt;/p&gt;

&lt;p&gt;I'm not a developer by trade, I'd never touched Godot before, and I leaned on AI to help me get over the learning curve.&lt;/p&gt;

&lt;p&gt;But I gave myself one hard rule that ended up shaping the entire project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero external assets.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No textures. No sprite sheets. No audio files. No music files.&lt;/p&gt;

&lt;p&gt;The whole repository contains none of them.&lt;/p&gt;

&lt;p&gt;Everything you see and hear in &lt;em&gt;Reactor Panic&lt;/em&gt; - a small arcade game where you sort plasma cores before the reactor melts down - is generated at runtime in code.&lt;/p&gt;

&lt;p&gt;Here's how I did it, including the parts that went badly wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do this to myself?
&lt;/h2&gt;

&lt;p&gt;Two reasons.&lt;/p&gt;

&lt;p&gt;First, I can't draw or compose, so "make it all procedural" was weirdly &lt;em&gt;easier&lt;/em&gt; than sourcing, creating, and licensing art assets.&lt;/p&gt;

&lt;p&gt;Second, and this is the part I didn't expect, when everything is code, everything can &lt;strong&gt;react&lt;/strong&gt; to the game state for free.&lt;/p&gt;

&lt;p&gt;More on that later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Drawing the Reactor
&lt;/h2&gt;

&lt;p&gt;All of the 2D art is rendered using Godot's &lt;code&gt;_draw()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The most involved piece is the containment dome. It isn't a sprite at all - it's shaded per cell like a tiny software renderer.&lt;/p&gt;

&lt;p&gt;For each cell, I compute a hemisphere surface normal, perform Lambertian diffuse lighting with a specular hotspot, add Fresnel-style rim darkening, and then &lt;strong&gt;quantise&lt;/strong&gt; the result into a handful of discrete steel bands so it reads as pixel art rather than a smooth gradient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hemisphere surface normal&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sx&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mid_x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;center_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;inv_half_w&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sy_sq&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Lambertian diffuse&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ndotl&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maxf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;light3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;light_val&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ndotl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;

&lt;span class="c1"&gt;# Fresnel rim darkening (surface curving away from viewer goes dark)&lt;/span&gt;
&lt;span class="n"&gt;light_val&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;lerpf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clampf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sz&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Quantise into discrete shade bands -&amp;gt; reads as pixel art&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;band&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clampi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;light_val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_band_f&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_bands&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shades&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;draw_rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Rect2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;px_f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row_y_f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;px_f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_bot&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;row_y_f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That final &lt;code&gt;draw_rect()&lt;/code&gt; call is important because it was the result of a mistake.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bug That Crashed a Flagship Phone
&lt;/h2&gt;

&lt;p&gt;My first implementation shaded the dome per pixel using &lt;code&gt;draw_line()&lt;/code&gt; for essentially every pixel.&lt;/p&gt;

&lt;p&gt;On desktop, it worked fine.&lt;/p&gt;

&lt;p&gt;On a Samsung Galaxy S25 Ultra, it hard-crashed the GPU.&lt;/p&gt;

&lt;p&gt;More than 10,000 draw calls per frame was simply too much.&lt;/p&gt;

&lt;p&gt;The fix was to stop thinking per pixel and start thinking in small grid cells (roughly 8×6 pixels) using &lt;code&gt;draw_rect()&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;The lighting calculations stayed exactly the same, but they were evaluated once per cell rather than once per pixel.&lt;/p&gt;

&lt;p&gt;That reduced draw calls from more than 10,000 per frame to around 500.&lt;/p&gt;

&lt;p&gt;The dithered band quantisation actually helped visually too. The chunkier cells looked intentional, like pixel art, rather than a low-resolution gradient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; on mobile devices, draw-call count matters far more than I expected.&lt;/p&gt;

&lt;p&gt;The full-screen effects - CRT scanlines, barrel distortion, chromatic aberration, an instability-reactive background with drifting dust motes, and heat shimmer - are handled by three small GLSL shaders.&lt;/p&gt;

&lt;p&gt;That's the one place where I let the GPU do the per-pixel work it is actually good at.&lt;/p&gt;




&lt;h2&gt;
  
  
  Synthesising the Audio
&lt;/h2&gt;

&lt;p&gt;I followed the same philosophy for sound.&lt;/p&gt;

&lt;p&gt;All ~15 sound effects are generated from raw waveform mathematics at runtime.&lt;/p&gt;

&lt;p&gt;Here's the entire generator for a simple sweep sound - a sine wave that glides between two frequencies with a linear fade-out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_gen_sweep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq_start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq_end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AudioStreamWAV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PackedByteArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lerpf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freq_start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq_end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;TAU&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;

        &lt;span class="n"&gt;_put_sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_make_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the envelope for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="nb"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you get a percussive blip.&lt;/p&gt;

&lt;p&gt;Layer in noise and a low rumble and you get an explosion.&lt;/p&gt;

&lt;p&gt;The background music is generated the same way, including a tension layer that ramps up as the reactor approaches meltdown.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Second Mobile Gotcha
&lt;/h2&gt;

&lt;p&gt;Generating all of those audio buffers up front (around 750,000 samples) blocked the main thread long enough for Android to throw an "Application Not Responding" warning on slower devices.&lt;/p&gt;

&lt;p&gt;The fix was simple:&lt;/p&gt;

&lt;p&gt;Generate the audio after the first frame renders.&lt;/p&gt;

&lt;p&gt;That way the app appears responsive immediately before doing the heavier processing work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Payoff: Everything Reacts for Free
&lt;/h2&gt;

&lt;p&gt;Here's the upside I didn't see coming.&lt;/p&gt;

&lt;p&gt;Because the dome colour is derived from a lighting value, I can feed reactor instability directly into that calculation and the entire structure gradually heats towards red as you get closer to failure.&lt;/p&gt;

&lt;p&gt;No separate damaged assets.&lt;/p&gt;

&lt;p&gt;No alternate sprites.&lt;/p&gt;

&lt;p&gt;It simply falls out of the same maths.&lt;/p&gt;

&lt;p&gt;The music becomes more tense.&lt;/p&gt;

&lt;p&gt;The CRT distortion intensifies.&lt;/p&gt;

&lt;p&gt;The gauges climb.&lt;/p&gt;

&lt;p&gt;One value drives the mood of the entire screen.&lt;/p&gt;

&lt;p&gt;That's the thing procedural generation gave me that pre-made assets wouldn't have:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The game isn't decorated - it's driven.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Built with:&lt;/strong&gt; Godot 4.6 / GDScript&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play in your browser (no install):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forcesensitivesaiyan.itch.io/reactor-panic" rel="noopener noreferrer"&gt;https://forcesensitivesaiyan.itch.io/reactor-panic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Available on Android and iOS:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google Play: &lt;a href="https://play.google.com/store/apps/details?id=com.aidoo.reactorpanic" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.aidoo.reactorpanic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;App Store: &lt;a href="https://apps.apple.com/us/app/reactor-panic/id6773935208" rel="noopener noreferrer"&gt;https://apps.apple.com/us/app/reactor-panic/id6773935208&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Happy to go deeper on any part of the implementation in the comments.&lt;/p&gt;

&lt;p&gt;The dome shading and the audio synthesis were by far the most enjoyable parts to figure out.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>godot</category>
      <category>gdscript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
