<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><title>ivysly.com - blog</title><link>https://ivysly.com</link><description>blog feed</description><lastBuildDate>Sat, 15 Aug 2026 12:01:36 +0000</lastBuildDate><item><title>why i still solo dev</title><link>https://ivysly.com/blog/why-i-still-solo-dev</link><description>&lt;p&gt;it&amp;rsquo;s because of money. for one, it takes a lot of money to hire someone to do something full-time if it is something they aren&amp;rsquo;t already obsessed with doing. but it&amp;rsquo;s true that i could probably afford to do so after selling a game that made a lot of money. the other issue is money.&lt;/p&gt;
&lt;p&gt;when developing and designing a game myself, for myself, my motivations are so transparent as to be tautological. i make games because i want specific games to exist so i can play them. that&amp;rsquo;s the top and bottom of it. i make games in order to play games i want to play. this entirely informs the design process. if some feature more makes the game into a game i want to play, it goes in the game. if it doesn&amp;rsquo;t, it doesn&amp;rsquo;t. hiring someone to be a part of this process creates an incentive problem. they aren&amp;rsquo;t necessarily contributing to the game because they want to play the specific game that comprises the specific elements they contribute. their contributions may categorically be those which the contributor doesn&amp;rsquo;t actually want to experience themselves, where mine cannot. this is fatal. once money is involved, i can only know that they are contributing because they want to make money. between me and this person, there is always a layer of distrust. they are incentivized to do as little as needed to meet perceived expectations and further their own career. whether or not they choose to act differently is an artifact of their personality, but the incentive structure doesn&amp;rsquo;t change. this is the unavoidable compromise of creative, commercial, hierarchical projects in capitalism, and the results are unavoidably inconsistent.&lt;/p&gt;
&lt;p&gt;of course there are many great games that are great because of a team&amp;rsquo;s shared commitment to a greater vision (most in fact). even if the specific ideas among individual contributors differ, the predominant attitude in these teams is of co-operation toward realizing a work of high quality. but these circumstances are hard to come by. my game made a lot of money, but it didn&amp;rsquo;t make enough that i can keep churning through teams until i happen upon a selection of weirdoes who A) share similar motivations to me, and B) have good taste, and C) have the skills to match. i could only cycle so many times before wasting too much time and money and creating ruin for myself. otherwise, i could continue working for free, alone. witness my decision in effect.&lt;/p&gt;
&lt;p&gt;i suspect it is getting harder now than ever for anyone to find a group of people to make great games with. it&amp;rsquo;s getting harder to merely survive for most people, and it was already more than hard enough. the games industry is falling apart. my dream to command a crew of like-minded obsessives seems fainter than ever. it felt easier when i was poor; to suggest a suicide mission is a lot simpler when the stakes are the same for everyone. now there is a power imbalance. i can no longer ask someone who barely lives off their paycheck to work for free, even though i, too, would be working for free. the circumstances between me and this person are fundamentally different now, despite my attitude and approach being more or less identical to the way they always have been. it&amp;rsquo;s a bit frustrating, but i don&amp;rsquo;t have much room to seriously complain when my peers are on food stamps.&lt;/p&gt;
&lt;p&gt;so it seems then that my last option outside of solo dev is to keep searching for other well-to-do creatives hiding in their own lofty towers in hopes i might convince any of them to waste some time with me. i haven&amp;rsquo;t had much luck. if you are a highly skilled craftsman with good taste, no monetary needs and lots of time, and for some reason you want to make a game with me, please email me at ivysly@protonmail.com&lt;/p&gt;</description><pubDate>Mon, 27 Jul 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/why-i-still-solo-dev</guid></item><item><title>thoughts about mixins and components</title><link>https://ivysly.com/blog/mixins-and-components</link><description>&lt;p&gt;i have been using Lua (now via &lt;a href="../blog/sologamedev-with-lisp"&gt;fennel&lt;/a&gt;) with &lt;a href="https://love2d.org/"&gt;LÖVE&lt;/a&gt; for a while, and i have found that one of the interesting and likeable things about Lua is how simple it is to implement mixins.&lt;/p&gt;
&lt;p&gt;mixins are an odd, rarely used but convenient concept in OOP similar to interfaces and components but not really exactly like either. a mixin is a class that is used by other classes to absorb its methods without directly inheriting that class.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;Enemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Object:extend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; the base class&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;CanBeHurt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Object:extend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; the mixin class&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;CanBeHurt:get-hurt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;damage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hurter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; a mixin method&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;print &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;.. &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;owie i got hurt by&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;tostring &lt;/span&gt;&lt;span class="nv"&gt;hurter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; for &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;tostring &lt;/span&gt;&lt;span class="nv"&gt;damage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; damage&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Enemy:implement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CanBeHurt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; implement the mixin on the base class&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Enemy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; create an enemy&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;e:get-hurt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ivy sly&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;; &amp;gt;&amp;gt; owie i got hurt by ivy sly for 100 damage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this &lt;code&gt;implement&lt;/code&gt; class method (as implemented in the very good &lt;a href="https://github.com/rxi/classic/blob/e5610756c98ac2f8facd7ab90c94e1a097ecd2c6/classic.lua#L33"&gt;classic&lt;/a&gt; library) directly injects all of &lt;code&gt;CanBeHurt&lt;/code&gt;&amp;rsquo;s methods to the &lt;code&gt;Enemy&lt;/code&gt; class, such that all instances of &lt;code&gt;Enemy&lt;/code&gt; can access the &lt;code&gt;get-hurt&lt;/code&gt; method. If &lt;code&gt;Enemy&lt;/code&gt; already has its own &lt;code&gt;get-hurt&lt;/code&gt; method, the &lt;code&gt;implement&lt;/code&gt; function will prioritize that existing method and quietly move on. &lt;/p&gt;
&lt;p&gt;there are some interesting things you can do with this. i ended up treating them similarly to components. in my implementation, mixins can be applied at the object level as well as the class level, and they have a special init method that is treated essentially as extended construction behavior. for example, some Enemies could randomly spawn with a FireAura mixin implemented &lt;em&gt;on the instance&lt;/em&gt; that initializes them with a &lt;code&gt;self.fire-radius&lt;/code&gt; value, adds an update callback to search nearby players to damage and a few methods to help with this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Object:extend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rng.percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; automatically call FireAura:mix-init on self with all parameters&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:instance-mixin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;FireAura.mix-init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;self.fire-radius&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; set to 50&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:add-update-callback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;each &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ipairs &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:get-nearby-players&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.fire-radius&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:fire-aura-attack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;FireAura.fire-aura-attack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;player:get-hurt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;when &lt;code&gt;Enemy&lt;/code&gt; spawns, there is a 25% chance for that instance to implement the &lt;code&gt;FireAura&lt;/code&gt; mixin, which calls &lt;code&gt;FireAura&lt;/code&gt;&amp;rsquo;s mix-init method on the &lt;code&gt;Enemy&lt;/code&gt; instance, and then injects all its methods (effectively just &lt;code&gt;fire-aura-attack&lt;/code&gt; in this instance). what i like about this system is its convenience; all methods and values are top-level. the mixin is effectively invisible. you can access &lt;code&gt;self.fire-radius&lt;/code&gt; directly from the &lt;code&gt;Enemy&lt;/code&gt; instance, use the mixin methods and behaviors, all without typing &lt;code&gt;FireAura&lt;/code&gt; all over the place. i&amp;rsquo;m not actually sure this is just a mixin anymore with all this extra behavior, but it&amp;rsquo;s effectively the same idea: inject the behavior from one class into another without dealing with complicated inheritance hierarchies. one could see now how this might be related to components, so let&amp;rsquo;s compare.&lt;/p&gt;
&lt;p&gt;components, in contrast to mixins, are usually more visible, and less entangled with the object that uses them. a component is typically expressed as another data structure explicitly contained by an object. imagine an alternative implementation of &lt;code&gt;FireAura&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Object:extend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;FireAura.new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;self.radius&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;FireAura.fire-aura-attack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;player:get-hurt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;FireAura.update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;each &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ipairs &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;owner:get-nearby-players&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.radius&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:fire-aura-attack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;self.components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; simple list of components&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rng.percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:add-component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fire-aura&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.add-component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; add it directly to our table so we can easily index it&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; e.g. self.fire-aura.radius&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;tset &lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; also add it to the component list for easy iteration&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;table.insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;each &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ipairs &lt;/span&gt;&lt;span class="nv"&gt;self.components&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;component.update&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;component:update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;in the business of safe, clean code, this is probably superior to mixins most of the time, if requiring some extra work. but nobody said gamedev has to be safe or clean—would i be using Lua if i cared about silly things like type safety?—so what other benefit might object composition have over mixins? i think the obvious answer is that components are non-destructive. you can add a component to an object, then later remove it without pain. mixins tightly couple with classes that implement them, making them less flexible at the instance level.&lt;/p&gt;
&lt;p&gt;but mixins are so convenient, aren&amp;rsquo;t they? i always optimize for laziness, that is, typing less, so i find the benefit of top-level field and method access hard to overstate. i am a big fan of duck typing. i&amp;rsquo;d much rather check for a simple &lt;code&gt;obj.fire-radius&lt;/code&gt; number and ignore when it&amp;rsquo;s &lt;code&gt;nil&lt;/code&gt; then have to go through the extra steps of checking something like &lt;code&gt;(and obj.fire-aura obj.fire-aura.fire-radius)&lt;/code&gt;. call me petty i guess. so here are some deranged ideas i have had about making components more mixin-like while remaining non-destructive.&lt;/p&gt;
&lt;h3&gt;option 1: unique field names&lt;/h3&gt;
&lt;p&gt;create a DSL to register every component with a name and the name of all of its fields, ensuring each field name is unique. something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;; add a new component to the global component registry with all field and &lt;/span&gt;
&lt;span class="c1"&gt;; method names exposed for easy checking &amp;amp; removal&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defcomponent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fire-radius&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; default value?&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fire-aura-attack&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;when you try to define a component with fields or methods that collide with the name of another component, it would error at compile time. doing this would let you apply components essentially as collections of string keys, and since there are no collisions, you wouldn&amp;rsquo;t need to contain them in separate structs. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rng.percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self:add-component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;FireAura&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fire-radius&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; default override?&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;print &lt;/span&gt;&lt;span class="nv"&gt;self.components.FireAura&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;gt;&amp;gt; true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;print &lt;/span&gt;&lt;span class="nv"&gt;self.fire-radius&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;gt;&amp;gt; 60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this is obviously insane. the main issue with this is how brittle it is. what if there are non-component field names we need to watch out for? what about overriding component behaviors on specific instances? we also no longer get a major benefit of components, which is that components can themselves be objects, with all the nice things objects let you do. instead this turns them in to a loose bag of key-value pairs. and despite technically being less destructive, it doesn&amp;rsquo;t &lt;em&gt;feel&lt;/em&gt; any better considering all the ways it could easily go wrong.&lt;/p&gt;
&lt;h3&gt;option 2: reduce declaration redundancy&lt;/h3&gt;
&lt;p&gt;a bit of a compromise. if we can front-load component access, then we can do roughly the same amount of typing, if a bit more. however i think we can do better than the following example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.some-method-that-uses-lots-of-components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; `let` is just fennel&amp;#39;s way of declaring multiple variables in &lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; sequence.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;comp1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.comp1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;comp2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.comp2&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;comp3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.comp3&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;comp4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;self.comp4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;i suspect we can cut this approximately in half with a hypothetical &lt;code&gt;let-self&lt;/code&gt; macro that assumes &lt;code&gt;self&lt;/code&gt; access.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.some-method-that-uses-lots-of-components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;let-self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;comp1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this would compile to the same code as above. where it gets messy is combining other variable declarations&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.some-method-that-uses-lots-of-components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;let-self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;comp1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;derived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp1.some-key&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; assume for some reason we couldn&amp;#39;t access these earlier:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;let-self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;comp3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;comp4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;suddenly we see more nesting and breaking up of variable declarations this way, making it hard to understand at first glance. maybe instead we could use a macro &lt;code&gt;let&amp;amp;&lt;/code&gt; that works like normal &lt;code&gt;let&lt;/code&gt; but allows opt-in self-keyed vars with a special identifier prefix:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.some-method-that-uses-lots-of-components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;let&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;comp1&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;comp2&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nv"&gt;derived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;comp1.some-key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;comp3&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;comp4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this feels cleaner but we run into a couple issues. the first issue is i can never remember where &amp;amp; is on my keyboard and i have to look at it half the time lmao. typing symbols tends to slow me down a little. then there&amp;rsquo;s the problem of dealing with identifiers that actually have &amp;amp; in the name. it feels dirty and slightly limiting. it also isn&amp;rsquo;t especially readable at a glance unless you format it very clearly.&lt;/p&gt;
&lt;h3&gt;option 3: evil metatable bullshit&lt;/h3&gt;
&lt;p&gt;never do this, but what we could do is override &lt;code&gt;__index&lt;/code&gt; on our &lt;code&gt;Enemy&lt;/code&gt; object to automatically find component values:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.__index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var &lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; search through all our components&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;each &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ipairs &lt;/span&gt;&lt;span class="nv"&gt;self.components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;. &lt;/span&gt;&lt;span class="nv"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;. &lt;/span&gt;&lt;span class="nv"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;not= &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; if a component with a value at that key exists, return that&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; otherwise do a normal __index check&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;. &lt;/span&gt;&lt;span class="nv"&gt;Enemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;Enemy.some-method-that-uses-lots-of-components&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; automatically finds the actual some-key in self.comp1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;derived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;self.some-key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this is obviously horrible because adding another component with a conflicting field name can silently change behavior in ways that are hard to debug. there are no unique benefits i can think of to doing this that are not covered by other options. don&amp;rsquo;t do it&lt;/p&gt;
&lt;h3&gt;option 4: grow up&lt;/h3&gt;
&lt;p&gt;well yes, maybe i should just get used to a component based object structure and using my fingers to type a little more code. it&amp;rsquo;s not that annoying. just a little more annoying than what i&amp;rsquo;m already doing right now. but maybe being annoyed is good sometimes in a time when it is so easy to let my brain smooth over and let trillion dollar robots do my typing and my thinking for me.&lt;/p&gt;</description><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/mixins-and-components</guid></item><item><title>i'm getting sick of sexy</title><link>https://ivysly.com/blog/im-getting-sick-of-sexy</link><description>&lt;p&gt;i saw the game &lt;a href="https://store.steampowered.com/app/2830030/MOTORSLICE/"&gt;Motorslice&lt;/a&gt; recently, and i can&amp;rsquo;t say it doesn&amp;rsquo;t look perfectly good at what it is setting out to do—though i have not played it—but reflexively i asked myself this question i seem to keep asking myself over and over again the last five or six years: why is the player character so conspicuously fuckable? i understand that sex sells, and i so too hate to knock someone for being true to their vision, but my main gripe about the material, from the critical perspective of a game designer (thus a narrative designer and a character designer and so on), my main gripe is how utterly &lt;em&gt;obvious&lt;/em&gt; all these indie gamedevs are getting about sex appeal, without any of the thematic justification needed to make it work. why, again, does the upcoming &lt;a href="https://store.steampowered.com/app/1445190/DoubleShake/"&gt;DoubleShake&lt;/a&gt; feature yet another doe-eyed, inoffensively curvaceous young anime woman, graciously stripped of any of the interestingly dissonant design elements present in her parallel Marina, protagonist of ancestral Mischief Makers, herself already a likeable, mostly unchallenging design? don&amp;rsquo;t we think it would be more interesting, daresay more subversive even, as this trend continues, to star in her place a big, burly, hairy, Mike Haggar sort of gentleman, or an old fat woman, or christ anything else at this point? try this exercise: any time you see one of these games, and there are many, imagine all the sexy anime creatures are Mike Haggar. it&amp;rsquo;s almost always an improvement. &lt;/p&gt;
&lt;p&gt;speaking of Big Michael: though his parents Capcom themselves are known for leading the industry in designing gorgeous video game babes, even going so far as to rework our own stupid superhero designs into items so fascistic in their beauty it feels uncomfortable to even acknowledge them as part of the same lineage as our own shoddy scrawls, yet they also, evidently, possess an incredible mastery over that which above all else great artists value: contrast and restraint. if you simply make everyone maximally cute and sexy, there is no dimension to it. there&amp;rsquo;s nothing to hold on to. one would quickly lose awareness of Psylocke&amp;rsquo;s beauty, of bawdy Felicia&amp;rsquo;s outfit and conduct, without the presence of the hunchback Zangief and his disgustingly bulging, scarred muscles, of the inhuman Shuma-Gorath, of savage Wolverine, of whatever the fuck is Amingo. the key aspect is balance. to its credit, Motorslice achieves this to some effect by contrasting the character against her huge, dirty, mechanical environment, but can we agree at this point that the &amp;ldquo;beautiful woman versus ugly world&amp;rdquo; trope is at least a little played out?&lt;/p&gt;
&lt;p&gt;i am fully aware of how easy i am to disregard here. my foremost artistic achievement is stick figures. but you don&amp;rsquo;t need to be a particularly skilled character designer to come up with a character more interesting and thematic than a silent woman who is attractive. i only humbly suggest to the budding indie developer to try something interesting instead of something boring&lt;/p&gt;</description><pubDate>Sun, 17 May 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/im-getting-sick-of-sexy</guid></item><item><title>there is no such thing as canon</title><link>https://ivysly.com/blog/there-is-no-such-thing-as-canon</link><description>&lt;p&gt;something that&amp;rsquo;s been a confusing annoying pain in my neck for the last forever is this cultural notion of ground truth in fiction, that somehow a collection of works and adaptations can form a singularly truthful throughline, as if the thing an episode of G.I. Joe has over those doubtlessly outnumbering works of fan fiction devoted to its musclebound subjects is, of all things, credibility. this is a grave category error approaching mass hysteria. we have been conditioned to accept this for decades, for one with the ever extending and obviously violent legislation and enforcement of intellectual property law (finally, we can publicly write a fan sequel to The Little Engine That Could in 2026 without being considered a criminal in the US) and it&amp;rsquo;s hackneyed at this point to even mention the Bible, which really is countless books written in different languages by thousands of different people, but still somehow one Word. truth has always meant nothing; did you know that Super Mario Bros. 3 is actually a stage play? never mind the fact that it&amp;rsquo;s a fucking video game&lt;/p&gt;</description><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/there-is-no-such-thing-as-canon</guid></item><item><title>i confess i have no taste</title><link>https://ivysly.com/blog/i-confess-i-have-no-taste</link><description>&lt;p&gt;as my status as an artist is self-appointed, in the same sense that a usurper rules &lt;em&gt;de facto&lt;/em&gt;—that is, by individually declaring it, and individual use of clumsy brute force to attain it, thus it is the truth, regardless of basic democracy or even common approval—maintaining an air of artisthood seems of greater importance to my ego than that of any natural artist i know. those are born artists, or people who understood their path from a young age, and were willing to work for it. i was never willing to work. i am only a suburban-born, middle-class dropout, raised in a household that revered art only in its humble, suburban, middle-class way, that of novel thrift-store lamps, family movies, Dave Grohl, my mother&amp;rsquo;s naïve yet proficient and charming portraits and life paintings and watercolors, my father&amp;rsquo;s technical mastery in copying metal riffs and organizing his music collection. my artistic life was steeped early in the invisible ubiquity of kitsch, which i loved with an almost underserved reverence, it being all i ever knew, yet so important has it been to me that culture considers my art one of its noble elements that i&amp;rsquo;ve tortured myself into making work out of what is supposed to be the greatest wellspring of joy in life, ART, further pained by the awareness that my shallow efforts will never elevate me above the truth that i am just a well-disguised Darger type: an uncultured, unknowing isolatee, disturbed by sexual and political insanity, and all-around too unwell to be a member of society, let alone the Canon. well, I&amp;rsquo;m tired of this stupid charade, and I&amp;rsquo;m convincing nobody. &lt;/p&gt;
&lt;p&gt;let it be known that i play fewer video games than working men with a tenth the means and time; that i read little and very slowly; that i just watch new movies at the cinema and random crap i pirate that &amp;ldquo;seems good&amp;rdquo;, and that a &amp;ldquo;classic&amp;rdquo; film to me is often closer to 1993 than 1941; that, by my observation, holistic consumption is a natural behavior for the natural artist, an obsession not just in his own work but for the art that defines him, yet an uncomfortable and annoying slog for me. there are moments of sublimity, yes, sometimes life changing moments, but they are crowded by an insecure trudging through works i force myself to enjoy, and analyze truthfully, all in the name of &amp;ldquo;improving my taste&amp;rdquo;, so i can be a better artist. because that is the whole point of all of it: i want to make art, and i&amp;rsquo;m concerned with making art that is good, and which i personally like. yet i don&amp;rsquo;t really care as much about absorbing external sources in the same way a natural artist does. my obsession is singular to making the thing, not looking at other things. deeply, i&amp;rsquo;m not a lover of art, but of the craft, so the art is in a sense my medicine or my homework—i must take it because it will help me with the thing i truly care about.&lt;/p&gt;
&lt;p&gt;but i&amp;rsquo;m ready to accept that i will gain little by plowing through the world of art at a pace or in a place not suitable for me, and while i extol the benefits of staying uncomfortable with practice and intake, it will do me no good to take so much or such bitter medicine. with this manifesto i only want to declare that i am of relatively few influences outside myself, yet many inside, so far as that, while maybe no longer an outsider artist, i am certainly and forever still an &amp;ldquo;insider artist&amp;rdquo;; there will be more classics i miss than which I&amp;rsquo;ll ever know—let alone reference—and, ultimately, it&amp;rsquo;s alright. i only want to re-learn how to love deeply the few things i can take in before i burn out or burst open. i&amp;rsquo;m ready to Let Me Enjoy Things.&lt;/p&gt;</description><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/i-confess-i-have-no-taste</guid></item><item><title>gameplay is art</title><link>https://ivysly.com/blog/gameplay-is-art</link><description>&lt;p&gt;let me first define art: art is whatever i think is art. creating games is an art. playing games is an art. gameplay is art and gamers are artists. artistry is itself a game that creates art. in the case of game development, artistry is a game that creates art that is a game that creates art.&lt;/p&gt;
&lt;p&gt;it is now commonly accepted that video game developers are artists. many people however don&amp;rsquo;t seem to think of gameplay (the action of a gamer playing a game) as art on the terms of art alone. most serious gaming as-vocation is in the form of competition (esports, speedrunning) or as a background activity for online entertainers. neither example is necessarily gameplay-as-art. there is an art to them, but it&amp;rsquo;s not innate to gameplay—it just involves gameplay to serve its own specific kind of art. all gameplay can be art on its own if only you framed it.&lt;/p&gt;
&lt;p&gt;games are still going through their Modern period. there is an abundance of self consciousness. the relationship between game and gamer has never been so uncertain. winning and losing is just a formal convention (and law, as video games are defined and bound by laws, unlike meatspace games which are built of breakable rules), a pretense of motivation with which the gamer can choose to play along or ignore completely. could a game be a tool? obviously yes. maybe we should ask ourselves when making a game: how can this be useful? i don&amp;rsquo;t mean useful in the sense of therapy. what I&amp;rsquo;m trying to ask is, in the case of the gamer-artist, how do we better make our games themselves tools of art? videogames as explicit creative medium is a mature form at this point, made unquestionably so by popular titles like Minecraft and Super Mario Maker whose gameplay is itself modal systems of creating play areas and then playing in them, but games without creative tools like these can still be recontextualized by their own residue like demo saves (emulation turned retro gaming into a demo sandbox retroactively) and even a game with no residue is changed by the presence of an audience, even if just the audience of the player. &lt;/p&gt;
&lt;p&gt;when designing a game, you are designing a space for gameplay with a certain kind or kinds of play in mind. but the designer-intended mode of play is an infinitely small subset of all gameplay. you can only account for nothing. all I&amp;rsquo;m suggesting is for you the designer to be aware of how the gamer can transform your game into their art, and design accordingly.&lt;/p&gt;</description><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/gameplay-is-art</guid></item><item><title>dream journaling for artists</title><link>https://ivysly.com/blog/dream-journaling-for-artists</link><description>&lt;p&gt;with some awareness of irony as i enter month 4 of my latest creative block, i thought i should write a little post about dream journals, my preferred tool for finding ideas. the practice of dream journaling feels enriching in the same way that making art feels enriching, and the best part is your brain does most of the work without any conscious effort. i&amp;rsquo;m not going to get into psychoanalysis or dream interpretation in this post, as that&amp;rsquo;s a more open-ended and personal process. you are free to practice on me if you want, as nearly all my dream recordings are &lt;a href="/dream"&gt;publicly available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;dreams produce the kinds of ideas and imagery that are nearly impossible for the conscious mind to generate unassisted, and by utilizing them in your art you are able to cultivate a style that is striking, personal, and unique. by paying attention to the contents of a dream, you are filling novel corners of your perceptual and thematic libraries, the places we look first when deciding on the form and content of an artwork. even as I currently struggle to make anything, dream journaling provides me an opportunity to bank ideas for later, a strategy that has worked out for me in the past; see: &lt;a href="/games/evil-egg"&gt;this game&lt;/a&gt;, directly inspired by &lt;a href="/dream/egg"&gt;one of my dreams&lt;/a&gt; and a work i consider among my best.&lt;/p&gt;
&lt;p&gt;dream journaling is a simple practice that is almost self explanatory: have dreams while you sleep, and record your memory of them when you wake up. there are of course several complicating factors and choices to make that prevent people from starting. i have gone through long periods of inactivity myself. here are the common blockers:&lt;/p&gt;
&lt;h3&gt;&amp;ldquo;i wish i could do it but i never have dreams&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;rejoice! all human beings on the planet (and most other animal species) have dreams every day. they just happen to be easier or harder for some people to access. the most obvious thing to take care of is your sleep hygiene. importantly, you need to make sure you&amp;rsquo;re getting enough sleep in the first place. sleep cycles occur in intervals of roughly 90 minutes. the most accessible dreams are had during REM sleep, which occurs at the end of a cycle, and the dreams you&amp;rsquo;ll remember are the ones that occur right before you wake. for many people, if they have a morning alarm, their body will restructure its sleep patterns so that they wake up consistently a little before their alarm actually goes off. the ideal scenario is that you get an appropriate amount of sleep (roughly 7-8 hours for most adults), and that you will be ending your last cycle, in REM sleep, right before your alarm goes off. this will maximize the chance you have a dream you remember, and is optimal for your health too—there is evidence to suggest that interruptions during deep sleep &lt;a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC5449130/"&gt;can be harmful&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;there are some medications and drugs (weed) that suppress dream recall. it&amp;rsquo;s usually still possible if you make an effort to remember, though, because you are absolutely still dreaming every night. you can also take certain medications or supplements to improve recall. melatonin is an obvious one. just don&amp;rsquo;t take more than 0.1mg or you&amp;rsquo;ll actively disrupt your sleep.&lt;/p&gt;
&lt;p&gt;don&amp;rsquo;t be discouraged if you don&amp;rsquo;t remember them frequently. if you cast your line you&amp;rsquo;ll eventually catch one. and as you start to remember your dreams, you&amp;rsquo;ll start to remember them more frequently and vividly.&lt;/p&gt;
&lt;h3&gt;&amp;ldquo;i have dreams I&amp;rsquo;d rather not remember&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;there are different solutions for this, depending on what you mean. lots of dreams are nightmares. if you&amp;rsquo;re just worried about having dreams where bad things happen, i suggest you push through this—not only are nightmares always full of interesting details, they can also be useful for introspection and working through difficult feelings and problems. i find nightmares more cathartic than dreams that just provide wish fulfillment, because one ends in relief and the other in disappointment.&lt;/p&gt;
&lt;p&gt;conversely, if your dreams are so severely unpleasant that they disrupt your quality of life and their effects on you persist when awake, then it&amp;rsquo;s time to see a professional. &lt;/p&gt;
&lt;h3&gt;&amp;ldquo;my dreams are just boring&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;no they aren&amp;rsquo;t. you think they are boring because when you&amp;rsquo;re dreaming, dream logic is mundane. in the short period after waking, you&amp;rsquo;re still half operating under this logic, and by the time you forget, you&amp;rsquo;re only left with the &lt;em&gt;feeling&lt;/em&gt; of the dream and that it was apparently boring. waking up and immediately recording what you dreamed has a twofold effect of bringing you into waking lucidity more quickly and allowing that fucked up dream logic to be put into context by real life. once you start recording, you&amp;rsquo;ll notice that you start to remember more about your dream, and further back—often the further you go, the weirder it gets. it&amp;rsquo;s not unusual for me to start at the end of my dream and prepend my recording with more and more details i remember about what came before. this makes sense, because typically we remember most what occurred in our dreams just before waking up. when trying to recall a dream to someone else, i think we go through this process without even realizing it.&lt;/p&gt;
&lt;h3&gt;&amp;ldquo;i want to do it but by morning i always forget&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;this is going to sound silly, but it works for practiced lucid-dreamers and it works for me: verbally affirm that you are going to journal in the morning. plant the idea in your head. you don&amp;rsquo;t have to fret about it. just remind yourself as you go to sleep about your plan to log in the morning. if you&amp;rsquo;ve set up your environment to make journaling the natural thing to do, you are more likely to eventually get started in the first place.&lt;/p&gt;
&lt;h3&gt;&amp;ldquo;i don&amp;rsquo;t want to write a bunch down the moment i wake up&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;well, it&amp;rsquo;s inevitable that you will have to put in a little work. what I&amp;rsquo;ve found is that it rarely takes very much writing to conjure the memory of a dream. i tend to focus on writing down the actual events and objects in a dream, because my memory will automatically fill in the details, vibes and emotions i felt when i was in it. however, it should be said that the more minimal you get, the more likely it is you won&amp;rsquo;t be able to remember it later. as of writing, there are only a few (maybe 3-4 out of 118) entries in my dream log that I cannot remember, and many of them are years old.&lt;/p&gt;
&lt;p&gt;you don&amp;rsquo;t actually have to write either. a voice memo works just as well for many people. i used to use a physical notebook, but now i just type them in a notes app on my phone, sometimes with speech-to-text. you could even draw a scene from your dreams. a dream journal isn&amp;rsquo;t necessarily supposed to be a highly detailed log of written events, because the actual entries themselves aren&amp;rsquo;t fully useful on their own—the memory they evoke is what creates a lasting impact. do whatever is easiest to you. set up your environment to make it as easy as possible. i open up the app i use before going to bed and place the phone next to my pillow, so that it&amp;rsquo;s already there and ready when i wake up.&lt;/p&gt;
&lt;p&gt;however, if you find you still just don&amp;rsquo;t enjoy doing it or get much out of it even after trying different things, then maybe you should just stop trying and move on. not everything is for everyone.&lt;/p&gt;</description><pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/dream-journaling-for-artists</guid></item><item><title>how to make a successful indie game</title><link>https://ivysly.com/blog/how-to-make-a-successful-indie-game</link><description>&lt;p&gt;tl;dr&lt;/p&gt;
&lt;div class="youtube youtube-16x9"&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/q-JgG0ECp2U?si=vNiiDxevmdXO34jF" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;i have dawdled on making this post for a couple years now because ultimately i am not qualified. i am a dysfunctional loser who stumbled into market success in the arts, maybe as undeserving a person could get if you believe in anyone deserving anything at all. it&amp;rsquo;s also hard to write this because it&amp;rsquo;s going to sound a lot like &amp;ldquo;fuck you, got mine&amp;rdquo;, but that&amp;rsquo;s not at all what i&amp;rsquo;m trying to do here. in fact, i am actually trying to help the reader to not make a huge mistake and throw their life away. i believe that in most respects i am not aspirational, but as time goes on i receive dm after dm, email after email from people asking me for advice, real, serious life advice, the &amp;ldquo;should i drop out of college and pursue game dev&amp;rdquo; kind of advice that could easily fuck up someone&amp;rsquo;s circumstances if taken to heart. this makes me feel a lot of ugly feelings and think a lot of nauseating thoughts, so i just want to lay it all out here so that i can stop sending the same depressing message to all the people—kids, mainly!—who look to me for guidance.&lt;/p&gt;
&lt;p&gt;you might think you want indie game development to be your #1 pursuit. okay. i will assume you don&amp;rsquo;t have the passive income or other means that would make it an easy decision. i hear some countries just toss you 20 grand if you say you are an artist. good for them. let me ask you to think about this question:&lt;/p&gt;
&lt;p&gt;are you content with being poor for the rest of your life?&lt;/p&gt;
&lt;p&gt;when i was a kid i always thought i was going to be a rock star. i wanted to be like my dad who was, to me, the greatest guitar player who ever lived, and a rock star himself. thus i spent most of middle &amp;amp; high school making crappy tunes in fl studio. i didnt care about school because i was going to be a rock star. i never had thoughts about getting a job (my parents hated their jobs, it wasn&amp;rsquo;t who they were, i could see it, and i decided i would never do that, i would do what i wanted to do) because i was going to hit it big. i spent my adolescense in a ridiculous dream that cost me my academic and social development until the obvious reality finally snapped me awake. no matter how good i was, and really, i was not that good, it didn&amp;rsquo;t matter, because the world is so huge and so many people want to be rock stars. how do i compete with someone smarter and more talented than me, someone who has more connections, more intrigue, more appeal, more money, more luck? &lt;/p&gt;
&lt;p&gt;i had to decide that i loved making stuff so much that i did not care if i would be poor and unknown forever. i only wanted to spend my time doing one thing, at any cost. anything was better than working. i am disabled (most people are) so i applied for social security income and was approved. for about 6 years i lived on around $9,000 USD a year, which at the time was already far below the poverty line. for two years i lived in a dining room, and i was lucky. the only thing i had was free time to grind away. that was all i wanted. the moral here is that i never had to ask anyone if i should do this. it was a shitty way to live and i can&amp;rsquo;t recommend it to anyone else, but i knew what i wanted, that i still want it, and that i will go back to living that way if i have to.&lt;/p&gt;
&lt;p&gt;the financial success of my financially successful game was a complete accident. i was not trying to make money with it. i&amp;rsquo;m a weak, lazy person and i had long given up entirely on any ambition to turn my hobby into a job. it happened to me, and i took the path of least resistance. this is not true for everyone who makes a successful game, but it should highlight the most important aspect of success: it can happen to anyone, and it can pass anyone by. you are not special, and i am not special except that i was lucky. i know someone will respond with some motivational bullshit about &amp;ldquo;making your own luck&amp;rdquo; which is true to the extent that you are more likely to win a jackpot if you play the machine 1000 times versus just once or none at all. it comes with a cost. you don&amp;rsquo;t force it with skill and hard work. skill and hard work are just the prerequisites to getting lucky at all.&lt;/p&gt;
&lt;p&gt;i was lucky in other ways too. i knew i wouldn&amp;rsquo;t be homeless if it came down to it. my family would have bent over backward for me and my siblings, as they have done before, but it would have destroyed us in the process. i am lucky to have a partner in my life who took care of me, kept me accountable, and in a way shared my absurd lifestyle. i am &lt;em&gt;luckier than most&lt;/em&gt; and i still gave up long before i happened to win the lottery. i&amp;rsquo;d return to shame and poverty if i had to, even though i rather like having a safety net and money to throw around. it would be my first choice. but i don&amp;rsquo;t think everyone needs to be this way to find their own version of success. you don&amp;rsquo;t have to quit school. you don&amp;rsquo;t have to quit your career. you can work on projects on the side. this doesn&amp;rsquo;t make you less of a game developer, less of an artist. you don&amp;rsquo;t have to make money doing something to love what you do. making art is not about grand gestures and taking huge risks, it&amp;rsquo;s about the love of the game and putting in the time that you do have. if you merely made something you are proud of, if you made a game you like to play, or even if you made a complete piece of shit that you hate, there&amp;rsquo;s success in there. that i got more money and recognition than another artist in the scene is a sick joke. i don&amp;rsquo;t have any more answers, any more insights. there is a bigger topic to explore about how people (in the US at least) are not allowed the humanity of leisure to do what they love, but i&amp;rsquo;m not good at talking about that. all i want to discuss in this blog post is my advice to those who keep asking for it. i say only sacrifice when you are sure, and be aware of the sacrifices you are about to make. don&amp;rsquo;t ask me if you should do what i did. if you have to ask&amp;hellip;&lt;/p&gt;</description><pubDate>Sat, 21 Feb 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/how-to-make-a-successful-indie-game</guid></item><item><title>public statement to all ice employees</title><link>https://ivysly.com/blog/ice</link><description>&lt;div style="font-size: clamp(3em, 10vw, 8em); font-weight: bold; line-height 1.1;"&gt;KILL YOURSELF&lt;/div&gt;</description><pubDate>Wed, 28 Jan 2026 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/ice</guid></item><item><title>solo gamedev with lisp</title><link>https://ivysly.com/blog/sologamedev-with-lisp</link><description>&lt;p&gt;this last month or so i have been using the &lt;a href="https://fennel-lang.org/"&gt;Fennel programming language&lt;/a&gt;, a Lisp dialect that transpiles to Lua. if you want the quick pitch: it&amp;rsquo;s a fast, imperative-oriented Lisp with macros that i think is perfectly suited to solo indie gamedev. i love it for all the reasons &lt;a href="../blog/daydreaming-with-lua"&gt;i love Lua&lt;/a&gt; and more.&lt;/p&gt;
&lt;p&gt;i had been interested in using a Lisp for some time—actually, had i the option, i would have probably picked a hypothetical LuaJIT With Macros first—but it always felt like there were hurdles and gotchas that prevented me from using it productively in game development. first is that the ecosystem is obviously pretty tiny for many Lisps. tooling, build systems and libraries can be a bit DIY, especially if you are not using Emacs (i might give it another go, now). Fennel circumvents much of this by just being Lua. &lt;a href="https://marketplace.visualstudio.com/items?itemName=JarodWright.strict-paredit-fennel"&gt;paredit&lt;/a&gt; + &lt;a href="https://marketplace.visualstudio.com/items?itemName=eduarddyckman.vscode-parinfer"&gt;parinfer&lt;/a&gt; with VS Code does the job of removing the parentheses pain well enough. this is the lesser issue. the bigger barrier is that Lisps are generally regarded as being on the functional side of programming languages, which, in the gamedev universe, means unknown, treacherous waters. games are highly stateful, highly imperative systems. it can be onerous trying to squeeze the slippery shape of a game into &lt;a href="https://prog21.dadgum.com/23.html"&gt;the result of a pure function&lt;/a&gt;. not to say that functional techniques have no place in gamedev, just that i find it difficult to apply them at the structural level. while some people are happy to take on such a challenge, i feel it is more practical for me to work in a perspective i&amp;rsquo;m familiar with. Fennel just so happens to feel exactly like Lua with a different syntax, because it is. i&amp;rsquo;m essentially doing the same things i was doing before, with a few trade-offs. this led me to a breakthrough: Lisp doesn&amp;rsquo;t have to be anything. there are very few limits on what they &lt;em&gt;can&lt;/em&gt; be. a Lisp has become in my mind solely defined as a direct representation of an AST made of &lt;a href="https://igor.io/2012/12/06/sexpr"&gt;s-expressions&lt;/a&gt;. you&amp;rsquo;ve probably seen s-expressions before. they&amp;rsquo;re just hiding in JSONs and &lt;a href="https://defmacro.org/ramblings/lisp.html"&gt;XMLs&lt;/a&gt;. you can write a Lisp with all the features of another language. it doesn&amp;rsquo;t even need to have a linked list data structure (Fennel&amp;rsquo;s lists only exist at compile time—even then, you spend most of your time just interfacing with Lua tables, with lists themselves in fact just being tables with some metadata). any other preconceptions you have about Lisp, you can safely let them go. &lt;a href="https://srfi.schemers.org/srfi-49/srfi-49.html"&gt;Lisps don&amp;rsquo;t even need to have parentheses&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fennel is not really at all a pure-functional or declarative language. due to the severe restriction of being a zero-overhead Lua transpiler, the Fennel language doesn&amp;rsquo;t even ship with any of its own functions. what it does have is access to all of Lua&amp;rsquo;s built-in functions and table operations, many of which are good old imperative, stateful operations. you very well &lt;em&gt;could&lt;/em&gt; turn Fennel into a pure, declarative language, or you could do something completely different. that&amp;rsquo;s because Fennel (and Lisp) isn&amp;rsquo;t really anything at all but a syntax. it doesn&amp;rsquo;t have to be anything until you make it something, and you are given carte blanche to do so with macros.&lt;/p&gt;
&lt;p&gt;with macros, a Lisp essentially becomes an extension of the programmer&amp;rsquo;s mental model of the program. it&amp;rsquo;s amazing how simple it is. you should probably exercise more prudence in teams, but as a solo developer, it&amp;rsquo;s pretty amazing to be able to freely add my own natural-language constructs to the language with no runtime overhead. for example, one of the most common mathematical operations i tend to do in game dev is dividing things by two. &lt;code&gt;somevar / 2&lt;/code&gt; shows up hundreds or thousands of times in my typical code bases. in Fennel (and most other Lisps), it&amp;rsquo;s dead simple to introduce a macro &lt;code&gt;(half somevar)&lt;/code&gt; that compiles to the same thing, both reducing symbol noise and increasing clarity of intent. there&amp;rsquo;s no function call overhead, so the only reason not to use it is when semantically it wouldn&amp;rsquo;t make sense. this i think is an incredible feature for idiosyncratic solo devs like me, because while you might make your code &lt;a href="https://marktarver.com/bipolar.html"&gt;unreadable for anyone but you&lt;/a&gt;, it can become highly readable &lt;em&gt;for you&lt;/em&gt;, and even more so quickly writeable. again, a Lisp can be &lt;em&gt;anything&lt;/em&gt;. this means it can be exactly what you want out of a programming language, with technically no concessions except that you might have to put in the work to get it there (there is a reason most DSLs written in Lisp tend to look a lot like Lisp).&lt;/p&gt;
&lt;p&gt;Fennel and &lt;a href="https://love2d.org/"&gt;LÖVE&lt;/a&gt; go very well together. i have found that plugging into my existing codebase was very easy. even getting an in-game REPL going only took a few minutes, and already i can sense the crazy amount of power it gives me to tweak things on the fly. and since it&amp;rsquo;s just Lua, it might be one of the faster Lisps when JITted with a great incremental garbage collector, very well suited to gamedev. being a solo dev, for me, means writing stuff quickly without spending too much time on tedious bookkeeping and careful structuring one might need to do in a larger team. for the lone gamedev, i think a controlled amount of yolo-coding is how you get shit made. this is a huge strength of Lisp.&lt;/p&gt;
&lt;p&gt;one funny problem with the switch from Lua is that now my engine uses three naming conventions; camelCase for the &lt;code&gt;love&lt;/code&gt; namespace, snake_case for my own preferred identifier style in Lua, and now kebab-case for all the symbols in Lisp. things can get pretty hairy when writing code that interfaces with all of these. nothing i can&amp;rsquo;t fix by rewriting my whole engine in Fennel of course.&lt;/p&gt;
&lt;p&gt;another small pain point is the notation for arithmetic. it&amp;rsquo;s just not as intuitive to read &lt;code&gt;a * b + c + d - e - f&lt;/code&gt; in the prefix notated form &lt;code&gt;(+ (* a b) c (- d e f))&lt;/code&gt;, but i suspect it could eventually end up being just about so, and i&amp;rsquo;m already developing adequate proficiency anyway. disregarding Lisp for this reason feels about as arbitrary and nitpicky as dismissing Lua for starting array indices at 1. you get used to it.&lt;/p&gt;
&lt;p&gt;as of writing i have only one completed project in Fennel. i just released a &lt;a href="../games/fishbone"&gt;jam game&lt;/a&gt; i made largely with Fennel, plugged in to my Lua LÖVE engine. i suspect my opinion will change in various ways as i continue to use it.&lt;/p&gt;
&lt;p&gt;anyway with my main theses out of the way i am excited to just jabber more about the ridiculous utility of macros. the real pervert crap. it&amp;rsquo;s often the case that you want to repeat the same complicated logic on multiple values across multiple lines, but introducing a lambda (in Lua, at least) may add an unacceptable performance overhead, and putting it somewhere else in the program restricts its utility as a closure. on the contrary, inline macros let you capture the context like a closure and duplicate logic without polluting your code with a bunch of repeated procedures (which could easily break should you forget to update all of them when you need to change it), with none of the overhead of creating and calling an actual function. as a very minimal example, imagine this naive code, in the input handling function for the player somewhere:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;up&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;down&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;in this example, it would be overkill to introduce a local function to simplify the logic, and is currently a lot of noise to repeat the logic for each direction. a macro can combine the best of both options while making the important logic much more clear. plus it keeps all relevant code in the same place without you needing to search for another function that exists somewhere else. it does all this with no runtime overhead, as the following snippet compiles to code roughly equivalent to the previous block:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;macro &lt;/span&gt;&lt;span class="nv"&gt;player-input-move!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;,&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;unpack&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fcollect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;select &lt;/span&gt;&lt;span class="nv"&gt;:&lt;/span&gt;&lt;span class="k"&gt;# &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dirx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;diry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;select &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;,&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;,&lt;span class="nv"&gt;dirx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;,&lt;span class="nv"&gt;diry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;))))))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;player-input-move!&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;up&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;down&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;this compiles to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;up&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;down&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input-held?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;move-player!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;the only meaningful difference being a few extra (cheap) multiplications, which could easily be refactored out as needed. i&amp;rsquo;d bet money that LuaJIT ignores multiplications by zero literal on hot loops anyway. when performance isn&amp;rsquo;t a concern, it usually will be cleaner to simply write a function, of course, but game dev performance is often death by a thousand cuts, with lots and lots of little inefficiencies that pile up. macros in Fennel allow you to define behavior &lt;em&gt;anywhere&lt;/em&gt; free of risk.&lt;/p&gt;
&lt;p&gt;you can get a lot more complicated than this too. i wrote DSLs for defining object classes and state machines. the latter only took an afternoon. I&amp;rsquo;ll leave you with what i am calling the &lt;a href="https://bsky.app/profile/ivysly.com/post/3m7jtgmthek2c"&gt;brohoof operator&lt;/a&gt;: a macro that divides two values in the opposite order they are passed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(macro \ [lhs rhs]
  `(/ ,rhs ,lhs))

(\ 2 1)
&amp;gt;&amp;gt; 0.5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sun, 14 Dec 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/sologamedev-with-lisp</guid></item><item><title>there is no grass to touch anymore</title><link>https://ivysly.com/blog/there-is-no-grass-to-touch-anymore</link><description>&lt;p&gt;&amp;ldquo;Disneyland exists in order to hide that it is the &amp;lsquo;real&amp;rsquo; country, all of &amp;lsquo;real&amp;rsquo; America that is Disneyland.&amp;rdquo;
–some asshole&lt;/p&gt;
&lt;p&gt;every day i go on a walk because my gf calls me fat if i don&amp;rsquo;t and it makes me feel bad so i do it. when i go outside for my daily shame walk i think about how there hasn&amp;rsquo;t been a time in my life longer than a week or two where I haven&amp;rsquo;t heard the sound of cars, haven&amp;rsquo;t seen a billboard, haven&amp;rsquo;t looked upon all the asphalt and concrete and wondered what the world looked like before we paved it all into stupid shitty roads and sidewalks.&lt;/p&gt;
&lt;p&gt;recently a bluesky post reminded me of something said by Shigeru Miyamoto in an interview:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;If it&amp;rsquo;s really nice outside, you should go play outside. And I tell that to people who want to be game designers as well, you know? If it&amp;rsquo;s a nice day, you know, go experience outside, because really, I think there&amp;rsquo;s an important factor that it&amp;rsquo;s your personal experience.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;and wow I bet that shit is so useful if you grew up in the Kyoto countryside 70 years ago but I think I speak for the rest of us when I say please keep your advice to yourself dumbass! there is no outside anymore. in a physical sense it is true I can drive to the river or the mountain (and truly my neck of the woods is in no way starving for natural features) but there is no longer any way to spend time in these places in good faith. how can I just go outside and &lt;em&gt;play&lt;/em&gt;? have you seen the &lt;em&gt;news&lt;/em&gt;? have you seen what people are doing to each other? outside is fake now. you go outside to pretend you aren&amp;rsquo;t still online in your heart. &lt;/p&gt;
&lt;p&gt;games are an escape from reality as much as prison is an escape from civilization. game design is about creating the most comfortable cell. maybe the most ethically designed game would offend so thoroughly the sensibilities of its gamer that he or she would wake up and finally, fully understand their physical and spiritual carceration and escape into the dinosaur world&lt;/p&gt;</description><pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/there-is-no-grass-to-touch-anymore</guid></item><item><title>on juice</title><link>https://ivysly.com/blog/on-juice</link><description>&lt;p&gt;put screenshake in your game. screenshake is the secret to a game that &lt;em&gt;feels good&lt;/em&gt;. if you don&amp;rsquo;t put it in your game, your game may not &lt;em&gt;feel good&lt;/em&gt;. the purpose of a game is to &lt;em&gt;feel good&lt;/em&gt;. we have perfected the formula to making a game &lt;em&gt;feel good&lt;/em&gt;. if you follow this formula your game will &lt;em&gt;feel good&lt;/em&gt; and thus it will be good. &lt;/p&gt;
&lt;p&gt;video games are just interfaces for sensation. we have extracted sweet sensation from pesky semantics. there&amp;rsquo;s no more need for intention. screen shake no longer has to convey &lt;em&gt;impact&lt;/em&gt;. it doesn&amp;rsquo;t need to convey anything. just do whatever you want. we are currently developing a game that is nothing but shaking and squishing and sloshing. baddies flash white when you swat them but also the goodies and everything else even if you don&amp;rsquo;t swat them. particle effects. stop thinking about it and start feeling about it. we are looking into haptic ecstacy.&lt;/p&gt;
&lt;p&gt;making a game is the real game. you need snapping and fizzing and swishing and zapping. i don&amp;rsquo;t care where you put it. put it anywhere. it&amp;rsquo;s a fucking &lt;em&gt;video game&lt;/em&gt;. did you know that in 2024 the games industry alone pulled in $184 billion dollars? why would you waste your time thinking when there is money to be made? look at all the other games around you: they are squishy and huggy and cozy and every time you do anything the game rewards you with an outpouring of sickeningly sweet &lt;em&gt;juice&lt;/em&gt;. your game needs to be sexual, it needs to simulate orgasm, and you need kids to buy it. what the fuck else are you making these for?&lt;/p&gt;</description><pubDate>Tue, 29 Jul 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/on-juice</guid></item><item><title>on scope creep</title><link>https://ivysly.com/blog/on-scope-creep</link><description>&lt;p&gt;two game studios behind two highly anticipated games announced those games&amp;rsquo; cancellations within the last couple weeks, those being indie studio Tendershoot&amp;rsquo;s Dreamsettler, the ambitious sequel to interactive fiction/internet simulator masterpiece Hypnospace Outlaw, and Riot-funded Hypixel&amp;rsquo;s Hytale, a Minecraftlike that was in development for over &lt;em&gt;seven years&lt;/em&gt;. the major problem both of these studios cited was unchecked ambition (a desire to make the &lt;em&gt;best game ever&lt;/em&gt;) and thus building these giant, untenable concepts and systems that ultimately demanded too much from the people working on them. the Vision can be so intoxicating it destroys any chance of a person actually making it real.&lt;/p&gt;
&lt;p&gt;I want to give an extended answer to this question my friend asked me:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;do you get scope creep feelings? how do you process them if so?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;to quickly outline the term: scope creep is a process by which the hugeness of a project grows and grows out of control, until it is no longer workable, as the people on the project are repeatedly struck with an insidious brainworm: &amp;ldquo;the project would be way cooler if we just added this one thing&amp;hellip;&amp;rdquo;. eventually the project becomes a clusterfuck of mostly cool new things that suffocate a now unrecognizable Core Vision, and often it is never finished. this has happened to you.&lt;/p&gt;
&lt;p&gt;this blog post makes a lot of assumptions. one is that you are or you know a game developer or some kind of artist or craftsman or architect who works in a medium that requires a lot of time and effort to produce a single finished work, and you do care that these works generally get finished and maybe even shared with the world. if you&amp;rsquo;re someone who is cool with taking your time, not worried about the finished product, and just making yourself happy adding a bunch of little things to a big thing, keep doing that. ignore any advice you know doesn&amp;rsquo;t apply to you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;do you get scope creep feelings?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I get scope creep feelings. I deal with them all the time, for every project. I don&amp;rsquo;t think they are avoidable. obviously we all want to make the best game ever. but the game in your head will never exist, so you have to compromise with reality.&lt;/p&gt;
&lt;p&gt;there&amp;rsquo;s always stuff that gets cut in the idea stage, stuff I&amp;rsquo;ll rip out of a game fully finished, and, in-between, a whole spectrum of scaling back cool ideas that are unjustified uses of time and effort, time and effort which could be better spent realizing the Core Vision.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;how do you process them if so?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;most games are about killing dudes. Given the right context, killing dudes is very cathartic. why shouldn&amp;rsquo;t that be true for killing ideas, assets, code, features, etc? &lt;/p&gt;
&lt;p&gt;throwing things out doesn&amp;rsquo;t have to be a bad thing. it&amp;rsquo;s a part of life. when I started learning in adulthood how to cook, I threw tons of food away. maybe because i made something inedible, or i bought too much and it went bad. over time I began to develop a positive relationship with throwing food away, because it meant I was cooking.&lt;/p&gt;
&lt;p&gt;after a short period of grieving the cool new thing I won&amp;rsquo;t be using in a game anymore, I find it easy to focus on the positives. there are plenty of advantages to cutting out a feature in a game. the most obvious and practical thing is that you reduce the workload for yourself. lower workload means you can spend more time on the stuff that really matters. consider all the loads of clusterfuck games that &lt;em&gt;did&lt;/em&gt; release and still suck because they couldn&amp;rsquo;t reign it in and focus on the Core Vision.&lt;/p&gt;
&lt;p&gt;I have developed this mindset over years and years of fatally overscoping. I started programming in 2015 with the goal of making games. each project was ridiculous. one of my first projects wanted to be similar to Cataclysm DDA. a 2018 project was supposed to be a Smash Bros—like. there are so many examples like this. I didn&amp;rsquo;t finish &lt;em&gt;my first game&lt;/em&gt; until 2021 (six years of nothing!!!) when I began working with &lt;a href="https://www.lexaloffle.com/pico-8.php"&gt;PICO-8&lt;/a&gt;, a game development environment that intentionally imposes &lt;em&gt;very&lt;/em&gt; strict limitations on the developer, and it forced me to keep my scope reasonable. I finished &lt;a href="https://ivysly.com/games/grippy"&gt;that game&lt;/a&gt; in about a month.&lt;/p&gt;
&lt;p&gt;some people feel like their time is wasted when they reach a dead end and they have to backtrack, that it is a negative outcome to be avoided. many are led to a scarily prevalent sunk-cost feeling and grow attached to bad ideas just because they fear scaling back so much. I just don&amp;rsquo;t think this is right. &lt;em&gt;backward progress is still progress&lt;/em&gt;. it&amp;rsquo;s surely not as efficient as realizing your vision of the game perfectly from start to finish, but nobody can actually do that. realizing you&amp;rsquo;ve scope crept and scaling it back is a natural part of working on a complex system. it is just a thick branch in a tree of mistakes—you don&amp;rsquo;t keep a wrong algorithm in your code, you take it out and replace it with something else or nothing at all. you don&amp;rsquo;t leave in typos.&lt;/p&gt;
&lt;p&gt;when scope creep happens you just have to focus on what you can get out it. what assets can you reuse? what ideas can you extract? if nothing else, what did you learn? I don&amp;rsquo;t remember a time when the answer to all these questions was &amp;ldquo;nothing&amp;rdquo;, so I posit that it&amp;rsquo;s never truly a waste. the Hytale developers will move on having if nothing else learned a very important lesson.&lt;/p&gt;
&lt;p&gt;It is important to note that I&amp;rsquo;m not against adding easter eggs and fun stuff just because. that&amp;rsquo;s what games are made of. I just think a game designer can benefit from weighing the time and effort cost of adding (or keeping) a feature with the amount of substance it adds to the game, how much it helps to complement and complete the Vision.&lt;/p&gt;
&lt;h2&gt;the process&lt;/h2&gt;
&lt;p&gt;recently I posted this to bsky:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bsky.app/profile/ivysly.com/post/3lrgs4kpkms2e"&gt;&amp;gt; I see good indie devs burn themselves out on huge projects and suddenly come out of hiatus with a little game that is way better and more focused than their prison opus and every time I want to scream: just do those games&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I followed up with: &lt;/p&gt;
&lt;p&gt;&lt;a href="https://bsky.app/profile/ivysly.com/post/3lrgu4en5c22l"&gt;&amp;gt; don&amp;rsquo;t make a big game until for you it&amp;rsquo;s a small game&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and I want to elaborate a little bit.&lt;/p&gt;
&lt;p&gt;first off, I think if you know what you want to do, you should do that. if you are willing to do what it takes, and you can afford to do it, then you should make the ambitious game of your dreams. I&amp;rsquo;m only asking people to consider what they want, if they haven&amp;rsquo;t already, and if they are willing to really work for it, and if they really know that they truly are willing, and so on. but I know I don&amp;rsquo;t really need to say that to them, because the people who know what they want don&amp;rsquo;t need me to tell them what they want. that leaves the rest of you suckers. especially those devs in question burning themselves out on big games—I only want to suggest an alternative that can be just as fun and much lower stakes. I have outlined a 2 step process:&lt;/p&gt;
&lt;p&gt;step 1. when you are deciding on a game concept, it can be difficult to know how big of a game you can make. I have a radical solution: look way, WAY smaller than you think you need to. unless you are an absolute newbie, there is definitely &lt;em&gt;something&lt;/em&gt; you know you &lt;em&gt;can&lt;/em&gt; make without question. maybe that&amp;rsquo;s pong, or even breakout. something of which you can envision the entire structure before starting any work. 100% confidence only. make that thing. if you are an absolute newbie, or you otherwise don&amp;rsquo;t have 100% confidence in pong, skip to step 2.&lt;/p&gt;
&lt;p&gt;step 2. when you are done making that thing, it&amp;rsquo;s time to do something completely antithetical to this blog post so far: start up a project with a big vague idea, experiment, add whatever you want without any thought to maintainability or even finishing the game. if you are the aforementioned absolute newbie, this is where you make pong instead. you (probably) will not finish the game, but I think this is the best way to safely push yourself without heartbreak. it will give you an idea of what you are capable of, so when you return to step 1, you will notice that you are able to envision a slightly bigger &lt;em&gt;entire game&lt;/em&gt; than you were last time. maybe substantially bigger. that&amp;rsquo;s it. return to step 1.&lt;/p&gt;
&lt;p&gt;this is the process I have come up with &lt;em&gt;accidentally&lt;/em&gt; over the last few years. accidentally because step 2 was always supposed to be step 1. it was always a feeling of, &amp;ldquo;okay, enough with these little projects, I&amp;rsquo;m going to make my opus, my Real Game. this time I can really do it.&amp;rdquo; then I noodle around for months and drop the thing because either it&amp;rsquo;s just too hard to implement the big ideas by myself or I just don&amp;rsquo;t have a cohesive enough idea to hold together such a big scope. subsequently, when I go back to making small games, I realize that the biggest game I&amp;rsquo;m 100% confident in making just got a little bigger.&lt;/p&gt;
&lt;p&gt;I have been, entirely by mistake, employing what I now believe to be a highly effective strategy for self-learning and improving my skills, and maybe even for eventually getting to making that big game my kid self always wanted to make. I present it, modified to reduce suffering, for anyone to try.&lt;/p&gt;
&lt;h2&gt;ethics of the opus&lt;/h2&gt;
&lt;p&gt;something i feel is important and kind of overlooked is that games take a really long time to make, when compared to most other forms of art. the barrier to entry is already really high. a 3 month timeline is on the low end for a finished game, outside of time-constrained game jam challenges which don&amp;rsquo;t really work as a real development strategy for &amp;ldquo;full size&amp;rdquo; games. I estimate most indie devs working on long term (non-gamejam/tutorial) projects are spending about a year or two. imagine if it took that long to write a single song, or paint a single picture. we are at a disadvantage in that way to composers or painters, because we only get so many two-year periods we can make games before we die or otherwise lose the ability. I suggest that it is inhumane to expect each other to meet a standard like that. life is very short for a game developer. we have to be much more picky about how we spend our time than a painter or a songwriter. we have much fewer chances to find our voices. this is, I think, maybe the most important reason for one to consider making smaller games.&lt;/p&gt;
&lt;p&gt;bottom line: check out PICO-8&lt;/p&gt;</description><pubDate>Sat, 28 Jun 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/on-scope-creep</guid></item><item><title>Evil Egg</title><link>https://ivysly.com/blog/evil-egg</link><description>&lt;p&gt;Evil Egg naked prostrating on the cold tile as the tub spout pours crashing into the open drain like a waterfall.&lt;/p&gt;
&lt;p&gt;Evil Egg eating to quell the nausea of overfullness and starving on dandelion green.&lt;/p&gt;
&lt;p&gt;Evil Egg knowing comfort under the flat white light of the aisle and checking out. Evil Egg decorating a martyr.&lt;/p&gt;
&lt;p&gt;Evil Egg sleeping as the warm rain blankets her in the wide dark.&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;a href="/games/evil-egg"&gt; &lt;img src="/images/evileggblog3.png" alt="evil egg"&gt; &lt;/a&gt;
&lt;/div&gt;</description><pubDate>Tue, 10 Jun 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/evil-egg</guid></item><item><title>daydreaming with lua</title><link>https://ivysly.com/blog/daydreaming-with-lua</link><description>&lt;p&gt;i think many programmers are conquerors. they want to bend reality to their will. to this end, making a software is an intense power fantasy, one where the programmer is given a problem and full control over a system to solve that problem, leveraging the unimaginable algorithmic power of the machine to obliterate tasks that would have taken human computers lifetimes of effort. &lt;/p&gt;
&lt;p&gt;in some capacity this is true also for creatives and really all people—there is an essential equivalence between making art and the process of daydreaming (the latter of which being a universal human experience) as commonly a form of wish-fulfillment. to develop a video game, i entertain both the power fantasy of programming and the wish-fulfillment of creative writing in a single process, to the immense satisfaction of my ego, and video games themselves achieve the highest potential for wish-fulfillment of any artistic medium.&lt;/p&gt;
&lt;p&gt;at the beginning of 2024 i made a resolution to ditch Godot. I had used it for 6 years or so, and for much of that time i held so much optimism for it and its future. but years of big and little issues wore me down, and finally i decided it was time to move on. i was done with doing things the Godot Way.&lt;/p&gt;
&lt;p&gt;instead i was going to build my own engine in FNA, a fork of XNA similar to Monogame, which uses the C# programming language. i really did try to do this, and i spent several months on the foundation for a 2d engine, but what i found is that C# and FNA became a sort of creative prison for me.&lt;/p&gt;
&lt;p&gt;you see the problem is that i can&amp;rsquo;t honestly describe myself as a &lt;em&gt;software developer&lt;/em&gt; but instead as an intuitive &lt;em&gt;game artist&lt;/em&gt;, who prefers freedom of expression without regard to the convention or maintenance needed of business software. what i need is rapid iteration, to unconsciously feel the impacts of tiny tweaks to the sensations of a game, not theorizing and calculating large swaths of changes all at once and waiting for the program to be &amp;ldquo;correct&amp;rdquo; before continuing.&lt;/p&gt;
&lt;p&gt;C# is not made for artists, it is made for businesses. this is true for the majority of general-purpose programming languages. C# is bureaucratic and cold, tough but fair. it&amp;rsquo;s not supposed to be a fun language because it is supposed to be a tool. it is the reflection of its creators who belong to a culture i reject as inhumane, thus its philosophy. so i have concluded that FNA just doesn&amp;rsquo;t meet the needs of the sole &lt;em&gt;game artist&lt;/em&gt; and could, worse, be actively harmful to artists who don&amp;rsquo;t know any better. programming languages are not just one-way communication, they necessarily communicate to you how you ought to think about data and procedures, and in the case of the game artist this means your creative output.&lt;/p&gt;
&lt;p&gt;the fact is, i wanted to try &lt;a href="https://love2d.org/"&gt;LÖVE&lt;/a&gt; long before i was ever interested in FNA. but something scared me about Lua, the simple, dynamic, interpreted programming language used by LÖVE. to me its simplicity hid intimidating depth. i had used it once before but i never really took the time to understand it. metatables, weird keywords, global magic methods—this was all very alien, 1-indexed arrays the least of my concerns. but i knew, deeply, even before my doomed tryst with C#, LÖVE was what was missing in my heart. &lt;/p&gt;
&lt;p&gt;i have learned since i started using it that Lua is more than just pleasant to write. i should have been tipped off by the name and brand of the LÖVE framework: soft colors, rounded edges, a sort of pneumatic, inviting atmosphere to its website, which playfully warns that its community &lt;em&gt;&amp;ldquo;sometimes gets too friendly&amp;rdquo;&lt;/em&gt;. all the clues are there. even the community-made libraries follow this theme, often explicitly; you will quickly find packages with names like &lt;em&gt;makelove&lt;/em&gt;, &lt;em&gt;love bone&lt;/em&gt;, &lt;em&gt;quickie&lt;/em&gt;, &lt;em&gt;moan&lt;/em&gt;, &lt;em&gt;hump&lt;/em&gt;, and yes, &lt;em&gt;hardon collider&lt;/em&gt;. this kind of thing might throw some people off, but after writing &lt;a href="https://ivysly.com/games/famulus"&gt;my second Lua-powered game&lt;/a&gt;, i have to say:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;i understand.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lua is a deeply erotic programming language. is this absurd to say? it is inviting and warm. there are no rules with Lua. it is not your boss but an equal and a companion. Lua says, &amp;ldquo;do what you want with me&amp;rdquo;. it is surprising but fluid. debugging is more feeling than rigor. even the name is feminine and flirtatious. it is everything that C# is not. Lua i come home to.&lt;/p&gt;
&lt;p&gt;sex is sort of like plugging in. despite having little in the way of modern package management, Lua allows the programmer to easily incorporate external library code unaltered, even with vast differences in structure, because Lua is highly polymorphic in both a mathematical and biological sense—that is, one API might be completely unrecognizable to the other, but you can still plug in. you could call that chemistry.&lt;/p&gt;
&lt;p&gt;i must recognize that the source of my daydream is the subconscious. it is impossible to ignore that my desire to make art is deeply entangled in the immediate, libidinal drive of the id, and barely held enough together by my ego to result in coherent output. is it absurd to model and encourage this with my tools? Lua is as satisfying in this way as you can get in the form of a programming language (see also Lisp) because what it allows you to do maps directly to the innermost desires of the human psyche. Lua was made for pleasure and play. while this may not be a good fit for the anti-human culture of business software, i think the benefit to creatives is by now self-evident.&lt;/p&gt;
&lt;p&gt;game artists are in a weird place where expression is steeped in procedure. art techniques are often formulaic, but the foundation of the art of programming is formula. this is where we make little prisons for ourselves. i would think the goal of the game artist is to instead build a bedroom.&lt;/p&gt;</description><pubDate>Tue, 04 Feb 2025 00:00:00 +0000</pubDate><guid>https://ivysly.com/blog/daydreaming-with-lua</guid></item></channel></rss>