<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Hello, I'm Igor</title><link>https://ikhotin.com/posts/</link><description>Recent content in Posts on Hello, I'm Igor</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>khotin@gmx.com (Igor Khotin)</managingEditor><webMaster>khotin@gmx.com (Igor Khotin)</webMaster><copyright>(C) 2025 Igor Khotin. This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Wed, 04 Apr 2029 00:00:00 +0000</lastBuildDate><atom:link href="https://ikhotin.com/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>neoBarbarians of the 21st Century</title><link>https://ikhotin.com/posts/2026/06/neobarbarians-of-the-21st-century/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/06/neobarbarians-of-the-21st-century/</guid><description>&lt;p>Fireworks are the things of the past, long gone and forgotten.
You really don&amp;rsquo;t need fireworks when drones and missiles explode over your head daily, so they were banned at the start of the war.
But that can&amp;rsquo;t stop certain individuals from launching them anyway.
I remember a couple of years ago we had an incident when someone wanted to have fun and launched fireworks nearby.
Half the neighbourhood almost shit their pants, suddenly hearing sounds resembling anti-aircraft fire and explosions. I just hope the police have found the ones responsible before the angry neighbours did.&lt;/p></description><content type="html"><![CDATA[<p>Fireworks are the things of the past, long gone and forgotten.
You really don&rsquo;t need fireworks when drones and missiles explode over your head daily, so they were banned at the start of the war.
But that can&rsquo;t stop certain individuals from launching them anyway.
I remember a couple of years ago we had an incident when someone wanted to have fun and launched fireworks nearby.
Half the neighbourhood almost shit their pants, suddenly hearing sounds resembling anti-aircraft fire and explosions. I just hope the police have found the ones responsible before the angry neighbours did.</p>
<p>On June 14, we celebrate my wife&rsquo;s birthday.
And even though we have no sentiment towards fireworks, I somehow knew the night won&rsquo;t be quiet, and we&rsquo;ll get our dose of flashes over our heads.
Last year, there was an air strike on Kyiv right on her birthday.
This year, I felt it would be just the same, since more than a week had passed since the last major strike on the city.
And russians have already accumulated a stockpile of drones and missiles.</p>
<p>In retrospect, I understand that the strike that night was inevitable.
Putin called Trump to congratulate him on his birthday.
By striking earlier, he could compromise the call.
But at the same time, he had to strike before the start of the G7 the next day as a show of strength.
The oil refineries and storage facilities deep inside russia burn daily, occupied territories and the south are facing fuel shortages,
which is not a good agenda for the start of G7.</p>
<p>So he decided that a powerful drone and missile strike on the capital, targeting prominent cultural locations including a UNESCO heritage site, would be a good idea. Something to change the agenda, so to speak.</p>
<p>Half-expecting the strike, we decided to skip the restaurant and opted
for food delivery. We still had the aftertaste of our experience
of a sudden air raid alert in the middle of a restaurant visit.
The establishment was closed in an emergency, and we hurried home
carrying boxes with our unfinished meal while listening
to explosions and drones flying above our heads.
(It was only a 10-minute walk home, but these 10 minutes felt
like eternity.)</p>
<p>This time, we can enjoy the food in the relative safety of our home.
I saved the bottle of wine for the night, so when the first missiles all of a sudden started to rain on the city, at least we could have a glass of wine to relieve the stress a little.</p>
<p>The hypersonic missiles were accompanied by the ballistic missiles, followed by cruise missiles and hundreds of drones.</p>
<p>So here I am, standing on my balcony with a glass of wine
and opening windows wide (to reduce the chance of shattering in case of a nearby explosion).
And I see a russian cruise missile flying over my city.</p>
<p>Well, the missile itself is not really visible in the night sky.
It reveals itself by dispersing flares when it enters a potential air defence sector. So I see the blackness of the missile cruising low and spreading bright flares in pairs left and right every second or so.
It glides out of my view behind apartment blocks.</p>
<p>At the same time, I hear a roaring sound of an approaching jet engine.
It was another cruise missile entering the city from a different angle.</p>
<p>The roar is suddenly abridged after a short burst from a nearby point defence flak (could be a Skynex, a Gepard, or maybe even a Tunguska).
The missile ended up in an explosion, painting the sky red.</p>
<p>I felt a powerful shockwave hitting my skin like a sudden blow of hot desert wind.
And for a moment I was afraid for the glassware I was holding in my hand - so powerful was the explosion. Now was the perfect time to refill the glass.</p>
<p>The explosions continued through the night, and only at dawn the cacophony contracted, with only a few drones still buzzing over the city.</p>
<p>Finally, we can put the kid to bed.</p>
<p>By that time, it was clear that it was a show-off terror attack targeting primarily civilian objects - multiple apartment blocks, houses, markets, and a school&hellip;</p>
<p>But this time the emphasis was on cultural sites - museums, books, one of the oldest film studios in Ukraine&hellip;
But the most prominent was Kyiv-Pechersk Lavra monastery, a historic site dating back almost a 1000 years. The roof of one of the buildings of the complex was set ablaze by a Shahed drone.</p>
<p>Moscovites are neobarbarians of the 21st century.</p>
<p>Not only have they appropriated our history, but they have also taken enormous effort in wiping out anything that contradicts their canonical view of events, perverted by centuries of khans, tsars, general secretaries, and now putin.
And a cave complex with churches and libraries created by monks in the 11th century, when there was nothing but a swamp in place of moscow, is a standing reminder that the core myth of the russian empire is hollow and lacks any substance.</p>
<p>Without Lavra they have no myth. And without myth they have no empire.</p>
<p>But all empires come to an end sooner or later.
Maybe we are witnessing the last struggle to resurrect a failing myth
of a fading empire - an empire that already crashed several times
and yet refuses to die in history, grabbing all it can with its bloody hands while sinking into the abyss. An undead zombie with rotten flesh
is trying to show the world that it is still alive and full of energy.</p>
<p>And as a true zombie, russia has no vision of the future, only the glimmers of the &ldquo;glorious&rdquo; bloody past. That is why putin always talks about years long gone, as if he tries to find some stable ground in the smelly swamp of contradictory myths that russian history has become.</p>
<p>The real moscovite history starts with Andrey Bogolubsky, who sacked Kyiv in 12th century, killing many inhabitants, stealing gold and icons from churches, burning books&hellip;
The vandal is canonized by the russian orthodox church now, a true russian hero.</p>
<p>Then moscovites swore allegiance to the Mongols while the latter burned Kyiv and Lavra to the ground.</p>
<p>Centuries later, there were russian orthodox church agents sent by Peter the Great to set Lavra library ablaze - to get rid of what&rsquo;s left of the real history and what might contradict the myth of the empire he is about to build.</p>
<p>Then the commies, following their scorched-earth tactics, blew up Lavra in 1941 after the Germans occupied the city.</p>
<p>It is nothing new. Putin continues the proud lineage of barbarism that lasted for centuries.
A true neobarbarian of the 21st century.</p>
]]></content></item><item><title>Kyiv Food Delivery Service</title><link>https://ikhotin.com/posts/2026/05/kyiv-food-delivery-service/</link><pubDate>Sun, 24 May 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/05/kyiv-food-delivery-service/</guid><description>&lt;p>It was ominous to start another game jam. After all, EVERY SINGLE TIME I&amp;rsquo;d joined a jam in the last two years, my city was under an aerial attack. This one was not an exception.&lt;/p>
&lt;figure>&lt;img src="https://ikhotin.com/img/2026/2026-05-24_aerial-attack.jpg"
alt="Map of aerial attack on Kyiv on May 24">&lt;figcaption>
&lt;p>May 24th attack on Kyiv&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>So in the timespan of 4 hours after midnight, we could hear hundreds of explosions, distant and close, from a wide range of munitions:&lt;/p></description><content type="html"><![CDATA[<p>It was ominous to start another game jam. After all, EVERY SINGLE TIME I&rsquo;d joined a jam in the last two years, my city was under an aerial attack. This one was not an exception.</p>
<figure><img src="/img/2026/2026-05-24_aerial-attack.jpg"
    alt="Map of aerial attack on Kyiv on May 24"><figcaption>
      <p>May 24th attack on Kyiv</p>
    </figcaption>
</figure>

<p>So in the timespan of 4 hours after midnight, we could hear hundreds of explosions, distant and close, from a wide range of munitions:</p>
<ul>
<li>
<p>a medium-range ballistic missile with MIRV</p>
</li>
<li>
<p>Zircon hypersonic cruise missiles</p>
</li>
<li>
<p>Kinzhal aeroballistic missiles</p>
</li>
<li>
<p>land-based Iskander ballistic missiles</p>
</li>
<li>
<p>sea-based Kalibr cruise missiles</p>
</li>
<li>
<p>land-based Iskander-K cruise missiles</p>
</li>
<li>
<p>air-launched Kh-101 and Kh-69 cruise missiles</p>
</li>
<li>
<p>various long-range attack drones</p>
</li>
</ul>
<p>These totaled to almost 100 various missiles and 600 drones. Hardly a precursor for a good night&rsquo;s sleep. The kid lay down on the floor near the wall, listening to the lullabies of the last four years.</p>
<figure><img src="/img/2026/2026-05-24_damaged-apartment-block.jpg"
    alt="One of the damaged apartment blocks in the morning with firefighting vehicles in the front"><figcaption>
      <p>One of the damaged apartment blocks in the morning</p>
    </figcaption>
</figure>

<p>It is another tragic and grim morning here in Kyiv. Neither my wife nor I has any energy to cook a meal&hellip; But even in the darkest moments, life continues - at least for the ones of us who survived. The restaurants and cafes wipe the ash from the morning fires, some of them clear the broken glass and put plywood instead, and go on with their business.</p>
<figure><img src="/img/2026/2026-05-24_glovo-courier.jpg"
    alt="A food delivery guy on a motorbike in front of a burning building"><figcaption>
      <p>Food delivery guy hurrying on a way to his customers</p>
    </figcaption>
</figure>

<p>Despite the devastation, the food delivery works still. You can always count on a fresh-cooked meal from a neighbourhood restaurant!</p>
]]></content></item><item><title>The Biggest Attack So Far</title><link>https://ikhotin.com/posts/2026/05/the-biggest-attack-so-far/</link><pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/05/the-biggest-attack-so-far/</guid><description>&lt;p>Last night concluded the biggest ruZZian attack so far.
It lasted for more than a day, when hundreds of drones,
wave after wave, entered Ukrainian airspace and rained
down on our cities. The grand finale was multiple salvos
of cruise, ballistic and aero-ballistic missiles on Kyiv.&lt;/p>
&lt;p>The resulting explosions could be heard through the night,
so we didn&amp;rsquo;t get much sleep. Particularly close missile explosions
created shockwaves, shaking windows and slamming doors inside
our apartment.
This time, our neighbourhood was not the lucky one - multiple
buildings were damaged. One Kh-101 cruise missile
hit an apartment block a couple of kilometers away
and caused the collapse of a whole section,
causing the death of 24 people (including 3 kids)
and injury of 48 more.&lt;/p></description><content type="html"><![CDATA[<p>Last night concluded the biggest ruZZian attack so far.
It lasted for more than a day, when hundreds of drones,
wave after wave, entered Ukrainian airspace and rained
down on our cities. The grand finale was multiple salvos
of cruise, ballistic and aero-ballistic missiles on Kyiv.</p>
<p>The resulting explosions could be heard through the night,
so we didn&rsquo;t get much sleep. Particularly close missile explosions
created shockwaves, shaking windows and slamming doors inside
our apartment.
This time, our neighbourhood was not the lucky one - multiple
buildings were damaged. One Kh-101 cruise missile
hit an apartment block a couple of kilometers away
and caused the collapse of a whole section,
causing the death of 24 people (including 3 kids)
and injury of 48 more.</p>
<p>By the time the dust settled over the rubble of fragmented bricks and concrete, more than 1500 drones and almost 60 missiles were detected.
Maybe not the biggest attack in terms of missiles used - we&rsquo;ve seen multiple attacks with 100+ missiles targeting only Kyiv. But certainly the biggest in terms of the quantity of munitions. And probably the biggest in terms of total explosives delivered in the package.
Most of these drones have 50-100kg warheads, so the total
might match the warheads of 200-300 missiles, if not their kinetic energy.
That tells us a lot about the growing role of long-range suicide drones
in modern warfare.</p>
<p>The war claimed more victims and continues to escalate. The &ldquo;dictatorship club&rdquo; is currently looking for ways to reassert itself and form the new multi-polar world order. And that means only more wars and misery in the future.</p>
]]></content></item><item><title>Winter Survival Challenge is Over</title><link>https://ikhotin.com/posts/2026/05/winter-survival-challenge-is-over/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/05/winter-survival-challenge-is-over/</guid><description>&lt;p>This Spring was relatively cold, just like this Winter.
But May, finally, brings warm weather, and that means
the Winter Survival Challenge is officially over.
Even though it was over for quite some time now,
I was waiting for the first really warm days to really claim it.&lt;/p>
&lt;p>And as I predicted in my mid-winter post, the hits on Ukrainian
Energy infrastructure will result in retaliatory strikes
on RuZZias oil facilities and tankers.
As we could see recently in Tuapse, Perm, Primorsk, Ust-Luga and other places.&lt;/p></description><content type="html"><![CDATA[<p>This Spring was relatively cold, just like this Winter.
But May, finally, brings warm weather, and that means
the Winter Survival Challenge is officially over.
Even though it was over for quite some time now,
I was waiting for the first really warm days to really claim it.</p>
<p>And as I predicted in my mid-winter post, the hits on Ukrainian
Energy infrastructure will result in retaliatory strikes
on RuZZias oil facilities and tankers.
As we could see recently in Tuapse, Perm, Primorsk, Ust-Luga and other places.</p>
<figure><img src="/img/2026/burning-tuapse.webp"
    alt="Burning Tuapse"><figcaption>
      <p>Burning Tuapse by Exilenova+</p>
    </figcaption>
</figure>

<p>As it turns out, oil products burn rather well.</p>
<p>This summer might be hotter than ruZZians ever wished for.</p>
]]></content></item><item><title>Keep Charging!</title><link>https://ikhotin.com/posts/2026/01/keep-charging/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/01/keep-charging/</guid><description>&lt;p>9:30PM&amp;hellip; Finally got the light. Electricity was out for 18 hours straight.
We are down to having only 2-3 hours of electricity a day with no predictable schedule.
So you don&amp;rsquo;t know when you&amp;rsquo;ll get it, and how long it&amp;rsquo;s going to last.
Now it is the usual buzz around the apartment - to charge everything we can -
phones, laptops, power banks, power stations, rechargeable batteries, toothbrushes&amp;hellip;&lt;/p>
&lt;p>And a car battery. I pulled it out of my car and brought it into the apartment just before the arctic air and the following ruzzian attacks.
Not an ideal solution, given the hazardous gases it can emit, but it is a potential backup option during long outages.
I can connect that battery to the solar port of one of my power stations and recuperate some additional energy just in case.&lt;/p></description><content type="html"><![CDATA[<p>9:30PM&hellip; Finally got the light. Electricity was out for 18 hours straight.
We are down to having only 2-3 hours of electricity a day with no predictable schedule.
So you don&rsquo;t know when you&rsquo;ll get it, and how long it&rsquo;s going to last.
Now it is the usual buzz around the apartment - to charge everything we can -
phones, laptops, power banks, power stations, rechargeable batteries, toothbrushes&hellip;</p>
<p>And a car battery. I pulled it out of my car and brought it into the apartment just before the arctic air and the following ruzzian attacks.
Not an ideal solution, given the hazardous gases it can emit, but it is a potential backup option during long outages.
I can connect that battery to the solar port of one of my power stations and recuperate some additional energy just in case.</p>
<p>Life right now is fully governed by the power availability&hellip;
First, you save any energy you can while waiting for a random window of opportunity.
Then, it is a fast-paced struggle to get the maximum out of whatever
electricity you have.</p>
<p>Hold fast and keep your power banks charged!</p>
]]></content></item><item><title>Unplesantries - A Drone Strike 100m Away</title><link>https://ikhotin.com/posts/2026/01/unplesantries-a-drone-strike-100m-away/</link><pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/01/unplesantries-a-drone-strike-100m-away/</guid><description>&lt;p>First, we heard a drone flying.&lt;/p>
&lt;p>Drones have passed right above our apartment block so many times that it was not something unusual.
But this time the drone loitered especially low.
The buzz got louder until it suddenly turned into a heavy explosion.
The air was violently disturbed by the shockwave as I saw a sinister red glow right above my building.
The sound of falling debris followed shortly afterward. I instantly realized that it was a hit - either at our apartment block or somewhere really close.&lt;/p></description><content type="html"><![CDATA[<p>First, we heard a drone flying.</p>
<p>Drones have passed right above our apartment block so many times that it was not something unusual.
But this time the drone loitered especially low.
The buzz got louder until it suddenly turned into a heavy explosion.
The air was violently disturbed by the shockwave as I saw a sinister red glow right above my building.
The sound of falling debris followed shortly afterward. I instantly realized that it was a hit - either at our apartment block or somewhere really close.</p>
<p>The kid was seriously startled this time, even though it was not his first explosion - he&rsquo;s already experienced thousands by now.
But there was certainly something different about this one that scared him so badly.</p>
<p>Reading the newsfeed, I realized that the drone hit the adjacent apartment block,
and not only that, it hit the same floor as ours. So it was a near miss for us.</p>
<p>Our building was really lucky this time - ruzzians struck our neighbours from the opposite side, and we were spared from most of the shockwave. Even all the windows survived this time.
That can&rsquo;t be said about many buildings in the proximity that got glass and sometimes whole window frames
knocked out by the explosion. And that is all amid dropping freezing temperatures.</p>
<p>My friend, who lives nearby, had his balcony windows shattered. He was getting some plywood and other materials from volunteers as I was chatting with him in the morning.</p>
<p>So now I can see a lot of plywood instead of glass in windows in our neighbourhood.
Well&hellip; Better dark than cold. It drops below -20C at night these days. Winter is coming.</p>
]]></content></item><item><title>The Arctic Survival Challenge</title><link>https://ikhotin.com/posts/2026/01/the-arctic-survival-challenge/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2026/01/the-arctic-survival-challenge/</guid><description>&lt;p>The jam stream is over!&lt;/p>
&lt;p>I can&amp;rsquo;t say it was unexpected. Ruzzians have been waiting for cold weather since the winter of 2022, and we were lucky to have relatively mild winters for 3 years in a row.
But any luck eventually runs out, and even with a globally warming climate, we got the winter of all winters.
With freezing temperatures we haven&amp;rsquo;t seen in decades.
Something I vaguely remember from my childhood - a lot of ice, piles of snow, and excruciating freezing cold.&lt;/p></description><content type="html"><![CDATA[<p>The jam stream is over!</p>
<p>I can&rsquo;t say it was unexpected. Ruzzians have been waiting for cold weather since the winter of 2022, and we were lucky to have relatively mild winters for 3 years in a row.
But any luck eventually runs out, and even with a globally warming climate, we got the winter of all winters.
With freezing temperatures we haven&rsquo;t seen in decades.
Something I vaguely remember from my childhood - a lot of ice, piles of snow, and excruciating freezing cold.</p>
<p>It might have been a beautiful sight and a perfect opportunity to finally get out the sleds rusting for many years in the warehouse. But the freezing arctic air is not the only thing that came from the north-east. What followed was a storm of ruzzian drones and missiles raining down on the city, targeting cogeneration stations, and plunging us into complete freezing darkness.</p>
<p>By the next morning we were in complete shutdown - no heat, no electricity, no water&hellip;
Also icy roads and prospects of temperature droping below -20C already this night.</p>
<p>As I&rsquo;m typing this on my typewriter, there is still no light or heating, and the temperature inside my apartment inescapably crawls down.</p>
<p><strong>The Arctic Survival Challenge Begins!</strong></p>
]]></content></item><item><title>Time out of Joint</title><link>https://ikhotin.com/posts/2025/12/time-out-of-joint/</link><pubDate>Sat, 27 Dec 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/12/time-out-of-joint/</guid><description>&lt;p>&amp;ldquo;The war continues to have a strange, somnambulistic quality,&amp;rdquo; wrote Mollie Panter-Downes about London of late 1939.
That was still a &amp;ldquo;phoney war,&amp;rdquo; and many still refused to believe that the old peacetime was over and the world was spiraling fast to the hottest war the world had ever seen.&lt;/p>
&lt;p>But war never changes. It is exactly the same now.&lt;/p>
&lt;p>We also refused to believe that the war is here, even while ruzzian forces were deploying all over Crimea, annexing the peninsula, and well-armed squads of &amp;ldquo;people of Donbas&amp;rdquo;, speaking with a suspiciously ruzzian accent, infiltrated from Crimea to the Donetsk region.&lt;/p></description><content type="html"><![CDATA[<p>&ldquo;The war continues to have a strange, somnambulistic quality,&rdquo; wrote Mollie Panter-Downes about London of late 1939.
That was still a &ldquo;phoney war,&rdquo; and many still refused to believe that the old peacetime was over and the world was spiraling fast to the hottest war the world had ever seen.</p>
<p>But war never changes. It is exactly the same now.</p>
<p>We also refused to believe that the war is here, even while ruzzian forces were deploying all over Crimea, annexing the peninsula, and well-armed squads of &ldquo;people of Donbas&rdquo;, speaking with a suspiciously ruzzian accent, infiltrated from Crimea to the Donetsk region.</p>
<p>Maybe it is human nature to hope for the best. I thought the international order is strong enough and there could be no major war in Europe in 21th century. But the war is not based on hope; it follows its own twisted logic. And eventually bombs, missiles, and drones blew up your naive dreams in little pieces.</p>
<p>War never changes.</p>
<p>Yet, I still have that feeling that this is just a fever dream, and the explosions I see and hear are nothing but sparks of neurons in my brain.
It has been almost 4 years, but my brain still refuses to accept the reality. The war really has that somnambulistic quality.</p>
<p>Just like in a dream, it is really hard to track time and place. Sometimes I struggle to pinpoint events on the timeline. There is a fault that splits it in half.</p>
<p>The world before the war is like memories of a movie I&rsquo;d seen, but at least I can place them in order.</p>
<p>And the world after is just a soup of events without proper timing. It is like a random noise out of constant air raids, explosions, and blackouts, plunging me into a state of constant stress and insomnia, and engulfing reality into a fuzzy and strange dreamscape-like limbo. There is no yesterday or tomorrow. There are no plans, cause any plan I might have always breaks at another air raid or blackout.
At some point, you just give up and leave all this planning to someone who actually has the future.
I can&rsquo;t catch a break. There is only grinding in short gaps between power outages and the next air raid on the city.</p>
<p>The time really feels out of joint.</p>
]]></content></item><item><title>Signals from Outer Space</title><link>https://ikhotin.com/posts/2025/11/signals-from-outer-space/</link><pubDate>Fri, 21 Nov 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/11/signals-from-outer-space/</guid><description>&lt;p>&lt;em>Today, my keyboard started to receive signals from outer space.&lt;/em>&lt;/p>
&lt;p>Well&amp;hellip; At least it felt like it.&lt;/p>
&lt;h2 id="bring-me-bluetooth">Bring Me Bluetooth!&lt;/h2>
&lt;p>It all started with another power outage, which happens frequently these days.&lt;/p>
&lt;p>Everything but the laptop went black - the lights, my second display, and a KVM switch.&lt;/p>
&lt;p>In a moment, the studio lights fell back to the batteries,
illuminating the room in an eerie red-blue glow.
The second screen is something I can manage without, but with the KVM out, I lost my mouse and keyboard.&lt;/p></description><content type="html"><![CDATA[<p><em>Today, my keyboard started to receive signals from outer space.</em></p>
<p>Well&hellip; At least it felt like it.</p>
<h2 id="bring-me-bluetooth">Bring Me Bluetooth!</h2>
<p>It all started with another power outage, which happens frequently these days.</p>
<p>Everything but the laptop went black - the lights, my second display, and a KVM switch.</p>
<p>In a moment, the studio lights fell back to the batteries,
illuminating the room in an eerie red-blue glow.
The second screen is something I can manage without, but with the KVM out, I lost my mouse and keyboard.</p>
<p>The mouse is an easy one, with a simple switch to the Bluetooth connection.
But this is not an option with my wired mechanical keyboard.
I had no desire to be lost in the cable jungle behind my table.
How can I locate that particular USB cable in low-light conditions
and then untangle it so it can reach the laptop directly?</p>
<p>Luckily, I had a wireless Varmilo Minilo VXT67 nearby and could connect it directly to the laptop, bypassing the KVM.</p>
<h2 id="here-comes-varmilo">Here Comes Varmilo</h2>
<p>So I connected the keyboard over Bluetooth.
Everything was fine until I began using it.</p>
<p><em>The system started to act weird.</em> In fact, it behaved somewhat like an unfortunate keyboard specimen I spilled my tea on back in 2003. It was producing random keystrokes even while I was not touching it. I was puzzled and confused - I couldn&rsquo;t remember spilling anything on this one.</p>
<p>I disconnected and reconnected it again. Same result. I rebooted the system. No fix.
The strange behavior continued. Every time I started to do something with the system,
the screen went crazy, pulling the GNOME launcher, switching the apps, tabbing between active UI elements, and sometimes typing in some random numbers&hellip;</p>
<h2 id="the-signals">The Signals</h2>
<p>Curious&hellip; Maybe I was hacked, and that is a practical joke someone is playing on me?
But then, these strange things were happening only when the keyboard was connected and I was using it. So it is not about the system, but the keyboard.</p>
<p>Once in a while, the focus would travel all over the active window
and end up on a text field. A second later, I can see numbers filling in -
<em>12321123221&hellip;</em> But not for long, faster than I can read them,
it would switch the app, change the keyboard layout, and show the GNOME launch menu&hellip; Triggered three times in a row&hellip;</p>
<p>Hm&hellip; Is that an alien civilization trying to communicate with me in cryptic form?
An intergalactic Aresibo message accidentally received by my keyboard
and transmitted to me over Bluetooth?</p>
<p>I was at the point when <em>my eye started to twitch</em>, and I was ready
to throw my expensive mechanical keyboard right into the wall, when I finally saw the pattern.</p>
<p>The numbers! <em>They are not random!</em> They are always the same - <em>12321123221&hellip;</em>
Following by the app switch, then a keyboard layout change&hellip;
Then the GNOME launch menu&hellip; Three more times&hellip;</p>
<p>And then I caught a starting trigger for all of that.
It always started the moment I touched the Windows button.</p>
<p>Wait a minute&hellip; It is a freaking MACRO that I&rsquo;m triggering!</p>
<h2 id="the-macro">The Macro</h2>
<p>It seems that the last time I&rsquo;d been setting up the Bluetooth connection,
I was confused about the actual keyboard controls.
I was used to the full-size or 80% TKL layouts, but this particular Varmilo is a 67-key Exploded model.</p>
<p>Probably, I inadvertently <em>enabled the macro recording while trying
to establish a Bluetooth connection!</em>
These cryptic <em>12321123221</em> are nothing but my attempts to select
a proper Bluetooth device with Fn+1/2/3&hellip; Only on this particular keyboard, it is Fn+Q/W/E instead (somehow, the selected Bluetooth device is highlighted by the glowing 1/2/3 keys, but selected with Q/W/E underneath).</p>
<p>Also, I recorded a bunch of shortcuts around it as well - like
app switches, layout selection, some Tabs, launcher activations, cursor motions&hellip; Quite a few keystrokes, I would say!</p>
<p>And these were replayed every time I touched the Windows key,
creating a poltergeist illusion and almost giving me a nervous breakdown.</p>
<p><em>Finally! The mystery is solved!</em></p>
<p>Also, I learned the special shortcuts for this Varmilo model.</p>
<p>RTFM.</p>
]]></content></item><item><title>Plywood Instead of Glass</title><link>https://ikhotin.com/posts/2025/10/plywood-instead-of-glass/</link><pubDate>Sun, 26 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/plywood-instead-of-glass/</guid><description>&lt;p>Long-strike drones are more dangerous than they seem.&lt;/p>
&lt;p>We&amp;rsquo;ve been harassed by ruzzian Shaheds for more than 2 years, and by now these drones are so mundane that we almost pay no attention to them. Sometimes, these attacks occur daily, in multiple waves that start in the evening and continue throughout the night. And when you hear the buzzing of drones and shooting all the time, you almost stop noticing and pay attention only when explosions approach too close for comfort (usually right over the head).&lt;/p></description><content type="html"><![CDATA[<p>Long-strike drones are more dangerous than they seem.</p>
<p>We&rsquo;ve been harassed by ruzzian Shaheds for more than 2 years, and by now these drones are so mundane that we almost pay no attention to them. Sometimes, these attacks occur daily, in multiple waves that start in the evening and continue throughout the night. And when you hear the buzzing of drones and shooting all the time, you almost stop noticing and pay attention only when explosions approach too close for comfort (usually right over the head).</p>
<p>A single drone might not be as dangerous as a cruise or ballistic missile. These things are really terrifying; they travel fast, hit hard, and carry a half-ton warhead. Shahed drones are relatively slow, but still carry a 90kg thermobaric warhead. The main problem is that there are so many more of them. When ruzzians launch 500 drones, they carry a punch of almost 100 cruise missiles. And drones are significantly cheaper.</p>
<p>Even a single unlucky hit by a drone can do a lot of damage.</p>
<p>Yesterday, the attack on the city was limited in scale. The night before, there were hundreds of drones and dozens of missiles. I couldn&rsquo;t sleep because of the loud explosions happening all around.</p>
<p>Yesterday, a few drones sneaked into the city on extremely low altitude. I heard explosions, but they were rather distant. Nothing too close to get me worried. But the relative calmness was misleading, and that night, more people died in our city than the night before.</p>
<p>A ruzzian drone hit an apartment building, killing 3 people and injuring 26 more, including 7 kids. The resulting fire spreaded so fast, the inhabitants had to jump out of windows to escape the burning inferno.</p>
<p>The explosion happened just across my parents-in-law&rsquo;s apartment, knocking out their windows. Now pieces of plywood occupy the places where glass used to be. And the folks say they are not even sure they have to install the glass back, expecting more strikes to come.</p>
<p>This is a sign of a city in the middle of a war - all over the place, you can see windows with plywood instead of glass.</p>
]]></content></item><item><title>Second Ballistic Strike this Week</title><link>https://ikhotin.com/posts/2025/10/second-ballistic-strike-this-week/</link><pubDate>Sat, 25 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/second-ballistic-strike-this-week/</guid><description>&lt;p>Explosion. Concussion. Rattling doors and windows. Car alarms triggered by powerful tremors.&lt;/p>
&lt;p>Such is another ballistic missile strike on Kyiv. The second one this week.&lt;/p>
&lt;p>The last one happened only 3 days prior and included a whole bunch of ballistic missiles,
cruise missiles, and drones. Explosions illuminated the sky throughout the night
and up to the next morning. Russians were hitting critical infrastructure all over the city,
and by 9 AM, the electricity was gone, and the hot water soon followed.&lt;/p></description><content type="html"><![CDATA[<p>Explosion. Concussion. Rattling doors and windows. Car alarms triggered by powerful tremors.</p>
<p>Such is another ballistic missile strike on Kyiv. The second one this week.</p>
<p>The last one happened only 3 days prior and included a whole bunch of ballistic missiles,
cruise missiles, and drones. Explosions illuminated the sky throughout the night
and up to the next morning. Russians were hitting critical infrastructure all over the city,
and by 9 AM, the electricity was gone, and the hot water soon followed.</p>
<p>And when the hot water supply was restored, they hit again.
It was 4 in the morning.</p>
<p>This time, incoming missiles landed in my part of the city.
That was loud.
They left huge craters and caused significant damage in the neighborhoods.</p>
<p><img src="/img/2025/2025-10-25_crater-after-ballistic-missile-hit.jpg" alt="ballistic-missile-crater">
<em>One of the craters. Nearby apartment buildings are lucky to survive - it seems like
the missile missed them by some 20 meters (photo by the National Police).</em></p>
<p>As of now, 2 people are dead, and a dozen more are injured.
The city is recovering from another awful night.</p>
]]></content></item><item><title>Collider.JAM War Release 2</title><link>https://ikhotin.com/posts/2025/10/collider.jam-war-release-2/</link><pubDate>Tue, 14 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/collider.jam-war-release-2/</guid><description>&lt;p>War makes me rethink planning.&lt;/p>
&lt;p>They say &lt;em>&amp;ldquo;no battle plan survives contact with the enemy.&amp;rdquo;&lt;/em> But as I know now, no single plan survives &lt;em>the touch of war&lt;/em>.&lt;/p>
&lt;p>As you know, I&amp;rsquo;m developing &lt;a href="http://collider.land">Collider.JAM Game Framework&lt;/a> to bring back the joy of programming in the dependency-intoxicated JavaScript world and demonstrate that web-first game development is not only possible, but viable and might even be superior in game jamming, creative coding and indie development.&lt;/p></description><content type="html"><![CDATA[<p>War makes me rethink planning.</p>
<p>They say <em>&ldquo;no battle plan survives contact with the enemy.&rdquo;</em> But as I know now, no single plan survives <em>the touch of war</em>.</p>
<p>As you know, I&rsquo;m developing <a href="http://collider.land">Collider.JAM Game Framework</a> to bring back the joy of programming in the dependency-intoxicated JavaScript world and demonstrate that web-first game development is not only possible, but viable and might even be superior in game jamming, creative coding and indie development.</p>
<p>My plan for the framework was to make a series of Development Releases to shape and stabilize the APIs before rolling out any &ldquo;stable&rdquo; releases people can rely on. Initially, it went very well with releases DR1 through DR11. I even had the feeling that we are almost there. Early Development Releases were chaotic with a lot of breaking changes. Somewhere by DR9 or 10 I&rsquo;d noticed almost no compatibility issues, and it was a pleasant revelation to see DR11 running a game developed for DR8 with no changes whatsoever. This was the stability I was looking for!</p>
<p>But the real world is not as stable as our APIs. And the war started.</p>
<p>Since the russian invasion, I&rsquo;ve learned that a black swan is not a one-off event. Black swans could arrive in flocks. And that is not only black swans you have to worry about, but also black helicopters, black fighter jets, black missiles, and black drones buzzing at night.</p>
<p>The war jolted the city to its core. Missile strikes, drone strikes, burned houses, apartment buildings, stores and warehouses, disruption of payment systems, shortages of food and fuel, blackouts, disruptions of heating and water supply&hellip; A fighter jet hit by a missile and falling to the ground in myriad burning pieces (the explosion was so loud that I honestly thought a missile actually hit my apartment building). It is a rollercoaster of events happening 24/7. No day-offs, no holidays, no sick leaves&hellip;</p>
<p>So I&rsquo;ve struggled to keep up with my plans. But I was restless to do something about it. A couple of months into the war, I&rsquo;d finally found my balance and got an inspiration. While I was no longer able to do both indie development and make regular updates to the game framework, I still could produce working snapshots based on my game roadmaps. While not a dedicated effort to develop the framework, I can still improve it while creating my games.</p>
<p>At this point, I&rsquo;ve got an idea to develop a series of games closely related to my war experience. It is a <strong>Z-Alert</strong> series (kind of a pun on <strong>Red Alert</strong>, only with a <strong>Z</strong>, which is a symbol of the invading ruzzian army), and the leading game is going to be <a href="https://github.com/invadium/anti-ballistix.mix">Z-Alert: Anti-Ballistix</a>, which I&rsquo;m creating right now exclusively during air raid alerts (kind of a personal challenge).</p>
<p><em>War Release 1</em> was out earlier this year and accumulated all the changes I&rsquo;ve made to <em>Collider.JAM</em> during the war. The changelog for this release is huge and diverse. It is quite obvious that there was no single roadmap I was following, just random changes, fixes, and improvements here and there.</p>
<p><em>War Release 2</em> ended up just the same. But with more breaking changes this time. I&rsquo;ve figured that it is a good opportunity to streamline the APIs while I&rsquo;m still in this havoc of events.</p>
<p>I&rsquo;m planning to create a lot of documentation and video tutorials. And I want the contracts and conventions to be stable and reliable, so that the materials stay relevant for a long time. You can expect more breaking changes in the upcoming WR3 and WR4, but very stable APIs in later releases.</p>
<p>I believe we&rsquo;ve captured the gist of it and could produce a platform that will be stable and compatible for years to come. Look for the upcoming releases. They will be truly awesome!</p>
]]></content></item><item><title>Just a Kludge in the Wall</title><link>https://ikhotin.com/posts/2025/10/just-a-kludge-in-the-wall/</link><pubDate>Sat, 11 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/just-a-kludge-in-the-wall/</guid><description>&lt;p>Today I saw &lt;a href="https://news.ycombinator.com/item?id=45547359">a HN discussion&lt;/a> on &lt;a href="https://github.com/BalajeS/WSL-For-FreeBSD">a WSL-like Windows subsystem for FreeBSD&lt;/a> and was stunned by the amount of genuine enthusiasm regarding that monstrosity.&lt;/p>
&lt;p>Sadly, it is just yet &lt;em>another kludge in the ivory tower of software bloat&lt;/em>. It is like all software is gravitating towards a single point of singularity, with all existing platforms collapsing into an incomprehensible black hole, sucking in our entire civilization.&lt;/p>
&lt;p>We might know well by now why &lt;em>the galaxy is silent&lt;/em>. Maybe all other civilizations went extinct after growing their software into a giant planet-consuming spaghetti-code monster nobody knew how to deal with. An unmaintainable blob of bloatware consuming more power than even a Dyson swarm can provide.&lt;/p></description><content type="html"><![CDATA[<p>Today I saw <a href="https://news.ycombinator.com/item?id=45547359">a HN discussion</a> on <a href="https://github.com/BalajeS/WSL-For-FreeBSD">a WSL-like Windows subsystem for FreeBSD</a> and was stunned by the amount of genuine enthusiasm regarding that monstrosity.</p>
<p>Sadly, it is just yet <em>another kludge in the ivory tower of software bloat</em>. It is like all software is gravitating towards a single point of singularity, with all existing platforms collapsing into an incomprehensible black hole, sucking in our entire civilization.</p>
<p>We might know well by now why <em>the galaxy is silent</em>. Maybe all other civilizations went extinct after growing their software into a giant planet-consuming spaghetti-code monster nobody knew how to deal with. An unmaintainable blob of bloatware consuming more power than even a Dyson swarm can provide.</p>
<p>I feel <a href="https://en.wikipedia.org/wiki/Great_Filter">the Great Filter</a> is inevitably approaching, and it is <em>going to be binary</em>.</p>
<p>There was no real point in <a href="https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux">Windows Subsystem for Linux</a> in the first place, except for desperate attempts by Microsoft to stay relevant in the cloud age. To take two huge and very different systems with all their bugs and idiosyncrasies, merge them (creating even more bugs and idiosyncrasies along the way), and call it progress? <em>I call it insanity.</em> Now only with <a href="https://www.freebsd.org/">FreeBSD</a>.</p>
]]></content></item><item><title>Another Total Blackout</title><link>https://ikhotin.com/posts/2025/10/another-total-blackout/</link><pubDate>Fri, 10 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/another-total-blackout/</guid><description>&lt;p>Last night was an emblematic one for Kyiv&amp;rsquo;s Fall. Heavy clouds dangled low, enveloping yellowing hills across the river. It was dizzling all day and into the night.&lt;/p>
&lt;p>Suddenly, a bright flash illuminated the October sky over the city, and interceptor missiles lacerated the heavy clouds. The glistering balls of rocket fire were diving into the low-hanging cloud ceiling, briefly highlighting the overcast skies. The roar of ascending engines followed. Then all hell broke loose.&lt;/p></description><content type="html"><![CDATA[<p>Last night was an emblematic one for Kyiv&rsquo;s Fall. Heavy clouds dangled low, enveloping yellowing hills across the river. It was dizzling all day and into the night.</p>
<p>Suddenly, a bright flash illuminated the October sky over the city, and interceptor missiles lacerated the heavy clouds. The glistering balls of rocket fire were diving into the low-hanging cloud ceiling, briefly highlighting the overcast skies. The roar of ascending engines followed. Then all hell broke loose.</p>
<p>Enormous explosions were shaking the city. More ballistic missiles came in. They were met with more interceptors. Hundreds of drones were advancing into the city from all sides. All targeting critical infrastructure.</p>
<p>I saw multiple flashes in the area of the power station and water facilities. They were followed by blue glow twinkling above the skyline. A few moments later, the whole city plunged into complete darkness. It spread as far as I can see from my window, except for a lonely traffic light that somehow found the energy to blink into the darkest night.</p>
<p><em>Another total blackout started.</em> No electricity. No water. No heating. Just like we had back in the Fall of 2022.</p>
<p>As I&rsquo;m writing this post 16 hours later, we finally got electricity back. Tap water followed - a very welcome improvement, since all we had were 2 full toilet tanks, a 12-liter aqua filter tank, and whatever water I&rsquo;d managed to accumulate in the tub after the strikes while it was still running.
Hot water is still missing though&hellip;</p>
<p>Some parts of the city are still without power. The emergency repair crews are working around the clock to fix the damage and bring the electrical grid back to full coverage.</p>
<p>And that is just the first major strike on Kyiv&rsquo;s energy infrastructure this season. I&rsquo;m sure that many more dark nights and bleak days will follow, as it was back in 2022, 2023, and 2024.</p>
<p><em>Missile Summer turning into Ballistic Fall.</em></p>
<p>However, it is no longer 2022, when Ukraine didn&rsquo;t have any means for long-range strikes, or 2024, when Ukraine refrained from striking deep into ruzzia.</p>
<p>Now, these strikes will not be left without a response. When your country is a gas station, it is unwise to start a fire at the neighbour&rsquo;s house.</p>
<p>Wait and see <em>the bright torches of burning oil</em> illuminating dull and neglected blocks of Soviet-era concrete apartment buildings all up to <em>the Ural Mountains and beyond</em>.</p>
<p>Hold fast and keep your power banks charged.</p>
]]></content></item><item><title>ReBasic Release 0.4</title><link>https://ikhotin.com/posts/2025/10/rebasic-release-0.4/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/10/rebasic-release-0.4/</guid><description>&lt;p>In 80 years of its existence, the software industry has become huge. It&amp;rsquo;s mass casts a gravity field on all spheres of human existence, and tremendous tide forces shred everything into a unified technological soup. Everything revolves around standardized platforms and frameworks now, and all-present forces of technological gravity mix features and ideas between them to the point it is hard to distinguish one product from another. Every website looks the same, and every mobile app follows the same &amp;ldquo;flat&amp;rdquo; design guidelines. Any opinionated software or unconventional idea will be pushed out by the antibodies of corporate greed.&lt;/p></description><content type="html"><![CDATA[<p>In 80 years of its existence, the software industry has become huge. It&rsquo;s mass casts a gravity field on all spheres of human existence, and tremendous tide forces shred everything into a unified technological soup. Everything revolves around standardized platforms and frameworks now, and all-present forces of technological gravity mix features and ideas between them to the point it is hard to distinguish one product from another. Every website looks the same, and every mobile app follows the same &ldquo;flat&rdquo; design guidelines. Any opinionated software or unconventional idea will be pushed out by the antibodies of corporate greed.</p>
<p>However, in virtual life, as well as in the real one, monocultures are good only for the short-term profit, but could be very dangerous in the long run. The whole idea that there is a single unified way of computing is fundamentally flawed (yet, we keep inventing silver bullets over and over again).</p>
<p>There should be efforts to preserve and modernize alternative computing models - the likes of <em>Forth</em> and <em>PostScript</em>, <em>Smalltalk</em> and <em>TCL</em>.</p>
<p><strong><a href="https://invadium.itch.io/rebasic">ReBasic</a></strong> is my humble effort to keep the fire of the long-forgotten interactive line-by-line model of programming that powered the entire 8-bit microcomputers era. When there was no IDE, no dependency management, no build pipelines&hellip; Just you, the machine blinking the &ldquo;READY&hellip;&rdquo; message, and a universe of possibilities hidden behind that simple interactive model.</p>
<p>I finally pushed <em>the version 0.4</em> that was baking the whole summer and most of September. I&rsquo;m very proud of the result - we&rsquo;ve playtested it with <em>JetPakBoy</em> and it really delivers the desired 80s retro-feel.</p>
<p><img src="/img/2025/2025-10-08.rebasic-release-0.4.png" alt="rebasic-release-0.4"></p>
<p>There are still features to be desired (like missing sound and documentation for some critical components). But overall, it is a solid BASIC reimplementation on the modern web that is usable and pretty extensively documented. You have online help on any command right in the console. There is also a bunch of pages available, describing particular aspects in great detail.</p>
<p><em>ReBasic</em>, the way it is today, could already play a role in introduction to programming - it is very accessible, easy to use, and mostly compatible with a huge body of 8-bit era BASIC code available online and in the old books.</p>
<p>Now I switch my focus back to <strong><a href="http://collider.land">Collider.JAM</a></strong> and will be returning back to <em>ReBasic</em> only sporadically to introduce a small feature, provide sample code or extend documentation as we explore <em>the BASIC universe</em> further together with <em>JetPakBoy</em>.</p>
]]></content></item><item><title>Missile Summer</title><link>https://ikhotin.com/posts/2025/08/missile-summer/</link><pubDate>Thu, 28 Aug 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/08/missile-summer/</guid><description>&lt;p>Last night turned out to be one of the loudest of this summer.&lt;/p>
&lt;p>Late evening, hundreds of drones started their attack on Kyiv in multiple waves.
I could hear the annoying buzzing of drone engines accompanied by bursts of anti-aircraft fire and occasional explosions after lucky hits.&lt;/p>
&lt;p>Then, the decibel level suddenly peaked.&lt;/p>
&lt;p>One moment, it was a dark, moonless night, then a bright light from the outside filled the room.&lt;/p></description><content type="html"><![CDATA[<p>Last night turned out to be one of the loudest of this summer.</p>
<p>Late evening, hundreds of drones started their attack on Kyiv in multiple waves.
I could hear the annoying buzzing of drone engines accompanied by bursts of anti-aircraft fire and occasional explosions after lucky hits.</p>
<p>Then, the decibel level suddenly peaked.</p>
<p>One moment, it was a dark, moonless night, then a bright light from the outside filled the room.</p>
<p>I sneaked out through the window to gaze on a series of missiles launched one by one into the skies over the city.
With their bright-shining engines leaving smoky trails, the missiles were rising high up to intercept the incoming targets.</p>
<p>I instantly realized that we are under ballistic attack.</p>
<p>The launch was followed by a characteristic chorus of rocket engines, which soon was accompanied by powerful explosions when the initial strike package was met high above.</p>
<p>The first wave of ballistic missiles was followed by another one. Then, yet another one.
Soon, radars detected the supersonic MiG-31K launching aeroballistic missiles towards us.</p>
<p>The attack was very intense and well-coordinated. Powerful explosions swept throughout the city.</p>
<p>Then, as suddenly as it started, it was over. But not quite, since ruZZian strategic aviation has already launched a bunch of cruise missiles, which were soon expected to enter Ukrainian airspace.</p>
<p>A new wave of explosions came closer to 6 AM.
Packs of cruise missiles were entering the city from multiple directions.
They were met by interceptors, ascending into the dark blue morning sky.</p>
<p>I saw a cruise missile get intercepted and turned into a pile of burning debris falling in long fiery arcs.</p>
<p>But some of them got through.</p>
<p>We heard powerful blasts closing in, followed by the growing sound of jet engines. A bunch of cruise missiles passed low above towards the city center. The fading sound of jet engines was followed by even more explosions.</p>
<p>And still it was not over. The disturbing buzz of enemy drones could be heard over the city.
There were shootings and detonations happening here and there.</p>
<p>It was already 7:30 AM, and yet another air raid alert was triggered by a new wave of drones entering the city.
But I was too tired to wait for it to be lifted.
The kid, woken by the deafening cruise and ballistic missile strikes, was back sleeping.
So I followed suit and went to bed, even though the sleep was occasionally interrupted by nearby blasts.</p>
<p>The attack on the city was repelled only by 9:30 AM, lasting for more than 12 hours.</p>
<p>Today I feel totally exhausted and unable to focus even on the simplest tasks.
The overall mood throughout the city is grim, as volunteers and emergency workers are clearing the rubble and digging out dead bodies.</p>
<p>25 people are dead so far, with some still missing.</p>
<p>Missile attacks this summer were especially atrocious - every single time a big apartment building or two are hit.</p>
<p>The bloodiest summer of this war in Kyiv so far.</p>
]]></content></item><item><title>Summer of BASIC</title><link>https://ikhotin.com/posts/2025/08/summer-of-basic/</link><pubDate>Fri, 22 Aug 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/08/summer-of-basic/</guid><description>&lt;p>When JetPakBoy got his break from school this summer
(and a deserved one - he has passed two grades in one year), we decided
to select a summer programming language to play with.&lt;/p>
&lt;p>I was oscillating between good, established options
and one of my language experiments.&lt;/p>
&lt;p>An established option gives a stable platform and a lot of materials to work with.
Platforms like Scratch, Python, Lua, and JavaScript seem to have everything you need -
stable implementation and well-documented APIs, a wealth of materials online,
versatile tooling, and good support.&lt;/p></description><content type="html"><![CDATA[<p>When JetPakBoy got his break from school this summer
(and a deserved one - he has passed two grades in one year), we decided
to select a summer programming language to play with.</p>
<p>I was oscillating between good, established options
and one of my language experiments.</p>
<p>An established option gives a stable platform and a lot of materials to work with.
Platforms like Scratch, Python, Lua, and JavaScript seem to have everything you need -
stable implementation and well-documented APIs, a wealth of materials online,
versatile tooling, and good support.</p>
<p>The problem is, none of those, except for Scratch, are
well-suited in a pedagogical context.
And Scratch for us is a done deal - JetPakBoy used it for several years
at school and has a pretty good grasp of the platform. So, there was no point in reiterating over a well-studied and understood option.</p>
<p>Then I&rsquo;ve dived deeper into possible alternatives that might be better suited
for learning programming. I&rsquo;ve looked at BASIC, LOGO, Smalltalk, Etoys, among others&hellip;</p>
<p>LOGO could have been a perfect language for programming introduction,
but it sadly missed its mark and never gained any real traction
in educational circles.</p>
<p>Smalltalk has modern implementations in the form of Squeak,
but it is too complex and lacks entry-level examples and tutorials.</p>
<p>BASIC, on the other hand, seemed to be a perfect choice.</p>
<p>It is designed as an introductory programming language
and, at some point, became the main language for 8-bit machines.
That firmly established it as a perfect language to study first
and formed a stable foundation in the form of books and magazine articles.</p>
<p>The main problem with BASIC is that with a variety of 8-bit platforms, it became too fragmented over time. Some archaic syntax idiosyncrasies also don&rsquo;t help.</p>
<p>The modern dialects, like Blitz Basic and Visual Basic, on the other hand, have moved it
too far away from its pedagogical origins into the realm of &ldquo;professional&rdquo; programming,
thus defying the whole purpose of the original design.</p>
<p><img src="/img/2025/2025-08-22_rebasic.png" alt="rebasic"></p>
<p>Therefore, for this summer, I&rsquo;ve resurrected <a href="https://invadium.itch.io/rebasic">ReBasic</a> - my own effort in bringing the original BASIC retro-feel and direct interactivity into a modern web shell.
And I&rsquo;m happy that recent changes delivered a stable platform that can run examples from classic BASIC books (like the classic Usborne BASIC series) with minimal changes.</p>
<p>This summer, me with JetPakBoy were able to Return to BASIC!</p>
]]></content></item><item><title>Another Deadly Strike on Kyiv</title><link>https://ikhotin.com/posts/2025/08/another-deadly-strike-on-kyiv/</link><pubDate>Fri, 01 Aug 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/08/another-deadly-strike-on-kyiv/</guid><description>&lt;p>Last night was terrible.&lt;/p>
&lt;p>Three hundred drones were attacking Kyiv through the night.&lt;/p>
&lt;p>&lt;img src="https://ikhotin.com/img/2025/2025-07-31_drone-and-missile-trails.jpg" alt="drone-and-missile-trails">&lt;/p>
&lt;p>Then, at 4 AM, when the drone attack was mostly repelled,
air raid alert lifted, and most people returned to their homes from bomb shelters,
ruZZians launched ground-based Kalibr-K cruise missiles from Kursk region.
Flying really low over swamps and rivers, the missiles converged on Kyiv from multiple directions
and started to hit targets all over the city.&lt;/p></description><content type="html"><![CDATA[<p>Last night was terrible.</p>
<p>Three hundred drones were attacking Kyiv through the night.</p>
<p><img src="/img/2025/2025-07-31_drone-and-missile-trails.jpg" alt="drone-and-missile-trails"></p>
<p>Then, at 4 AM, when the drone attack was mostly repelled,
air raid alert lifted, and most people returned to their homes from bomb shelters,
ruZZians launched ground-based Kalibr-K cruise missiles from Kursk region.
Flying really low over swamps and rivers, the missiles converged on Kyiv from multiple directions
and started to hit targets all over the city.</p>
<p>Once again, one missile hit just another apartment building, collapsing a whole section
and burring people underneath the rubble.</p>
<p><img src="/img/2025/2025-07-31-destroyed-by-missile.jpg" alt="damaged-building"></p>
<p>The blast wave hurled a teenage girl sleeping in her bed and threw her out.
She fell from the 9th floor and luckily survived with only a broken leg and minor injuries.
Her parents were not that lucky and died under the collapsing concrete.</p>
<p>Many other apartment buildings were damaged by missiles and drones
all over the city. But my neighbourhood was spared this time.</p>
<p>UPDATE: 31 dead bodies in total were found after clearing up the debris and rubble.</p>
]]></content></item><item><title>Nearby Shahed Strike</title><link>https://ikhotin.com/posts/2025/07/nearby-shahed-strike/</link><pubDate>Sun, 27 Jul 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/07/nearby-shahed-strike/</guid><description>&lt;p>Yesterday, a ruzzian Shahed drone damaged a nearby apartment building.&lt;/p>
&lt;p>We had damage nearby before - from falling intercepted cruise missiles and drones.
Just a few months before, the falling debris damaged an apartment building across the highway.&lt;/p>
&lt;p>But this time it was much closer than before.
The falling debris damaged an apartment building on my block, just a few hundred meters away.&lt;/p>
&lt;p>A strange thing is that it was not the largest explosion happened recently in the area.
We had drones intercepted just right overhead, and the resulting explosions were subjectively much louder.
Then I was seeing bright flashes in the skies above and felt the resulting shockwaves
passing through my body.&lt;/p></description><content type="html"><![CDATA[<p>Yesterday, a ruzzian Shahed drone damaged a nearby apartment building.</p>
<p>We had damage nearby before - from falling intercepted cruise missiles and drones.
Just a few months before, the falling debris damaged an apartment building across the highway.</p>
<p>But this time it was much closer than before.
The falling debris damaged an apartment building on my block, just a few hundred meters away.</p>
<p>A strange thing is that it was not the largest explosion happened recently in the area.
We had drones intercepted just right overhead, and the resulting explosions were subjectively much louder.
Then I was seeing bright flashes in the skies above and felt the resulting shockwaves
passing through my body.</p>
<p>This time, the explosion was not that loud, probably because it happened on the opposite side
of the damaged building, shielding me from the shockwave.
Then it was followed by the secondary explosions of the falling debris.</p>
<p><img src="/img/2025/2025-07-28.drone-hit-damage.jpg" alt="damaged-building"></p>
<p>5 people were injured by the explosions, with multiple apartments damaged.
Luckily, the strike was not followed by a big fire.
What started to burn was swiftly localized.</p>
<p>When I&rsquo;d visited the site the next morning, most of the fallen debris and shattered glass
were already cleared with sappers swiping nearby lawns for fallen explosives and submunitions.
Workers of the ground-level store were busy clearing up shattered glass inside.</p>
<p>Another busy morning.</p>
]]></content></item><item><title>Fragile Base Class Problem</title><link>https://ikhotin.com/posts/2025/07/fragile-base-class-problem/</link><pubDate>Sun, 13 Jul 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/07/fragile-base-class-problem/</guid><description>&lt;p>Early 90s saw an unprecedented push towards object-oriented systems. General concensus was that everything must be object-oriented, and by object oriented, everyone meant C++.&lt;/p>
&lt;p>There was no other major contender. Smalltalk, which popularized the OO approach in the first place, had never seen general adoption and was confined to niche, self-contained, all-in-one systems. Early Smalltalk implementations by Xerox PARC clearly showed what pervasive object-orientation meant - the world of objects exchanging messages in a persistent environment. No primitive values, no pointers, no operating system&amp;hellip;
It is a different reality, never appreciated by the tech world, that went in the other direction, trying to superimpose object-oriented elements on top of the existing ecosystem. That is how we got C++, Objective-C, Object Pascal, Visual Basic, and other retro-objectified technologies.&lt;/p></description><content type="html"><![CDATA[<p>Early 90s saw an unprecedented push towards object-oriented systems. General concensus was that everything must be object-oriented, and by object oriented, everyone meant C++.</p>
<p>There was no other major contender. Smalltalk, which popularized the OO approach in the first place, had never seen general adoption and was confined to niche, self-contained, all-in-one systems. Early Smalltalk implementations by Xerox PARC clearly showed what pervasive object-orientation meant - the world of objects exchanging messages in a persistent environment. No primitive values, no pointers, no operating system&hellip;
It is a different reality, never appreciated by the tech world, that went in the other direction, trying to superimpose object-oriented elements on top of the existing ecosystem. That is how we got C++, Objective-C, Object Pascal, Visual Basic, and other retro-objectified technologies.</p>
<p>However, the zeitgeist of the era was that OO was the future, and all other programming models were destined to be extinct, swept aside by the superior approach.</p>
<p>The core problem of that worldview was the existing operating systems. They were far from object-oriented. Smalltalk solved that issue by dropping the operating system concept altogether by providing the user with a completely enclosed environment with no need for an OS.</p>
<p>This approach will never work with the traditional computing model that was already built around the existing operating system-app dichotomy. The 90s saw multiple attempts in object-oriented operating system design. It is fascinating, that most of them had the Apple pedigree.</p>
<p>Struggling to revamp the existing Classic MacOS that was showing its age, Apple launched the Pink project later morphed into Taligent Inc. - a joint venture with IBM. It was meant to create an innovative object-oriented operating system and programming environment, but failed to produce a viable product.</p>
<p>Another object-oriented operating system attempt was made by NeXT. The resulting NextStep OS could be considered rather a lucky one, since it still exists, although in a heavily mutated form.</p>
<p>Steve Jobs was fascinated by OO-programming, stating in interviews, that he was so blinded by the GUI during the Xerox PARC demo, he missed other important parts - networking and object-oriented programming. A decade later, he decided to remediate that by taking Objective-C and building an object-oriented application environment.</p>
<p>Retrospectively, Objective-C looks like a weird choice, since we all know that the industry moved forward with C++. But back then, it was not so obvious, and Objective-C looked much more attractive in the NeXT context. Fully backward-compatible with C and with Smalltalk-like dynamic message dispatch, it seemed more suitable for NextStep object-oriented tools like Interface Builder.</p>
<p>But NextStep object-orientation was just a facade. Only API Kits were object-oriented. Beneath that layer lay a rather unusual breed of BSD UNIX running on top of the Mach microkernel with Display PostScript instead of X11 for graphics. It might not be a traditional System V, nonetheless still a UNIX, and hardly the next generation object-oriented OS everyone was talking about.</p>
<p>The third system was also built mostly by Apple refugees. It is BeOS from Be Inc.</p>
<p>They took a similar approach to NeXT, only with C++ instead of Objective-C and with a native graphics API instead of PostScript (although they initially played with Sun NeWS before deciding to go a separate way). On BeOS, you also have Kits creating an object-oriented facade around the mostly C-based kernel, drivers, and low-level services. Although one could argue it is more object-oriented than NextStep, since you don&rsquo;t have a full-blown UNIX and PostScript infrastructure running underneath, just a POSIX API compatibility layer with bash and some regular UNIX tools.</p>
<p>What fascinates me is that in an interview for MacTECH, Erich Ringewald, the lead software architect at Be Inc. back then, was talking about the fragile base class problem and the approaches they tried at Be to avoid it while designing BeOS app kits.</p>
<p>It is a problem when changes to the base class can break functionality down the inheritance chain. And the fact that they are talking about it in the mid-90s clearly shows that problems with object-oriented programming, like the fragile base class problem, were already well understood back then (I bet the Smalltalk community had already known those back in the 80s, but who listened to them really?).</p>
<p>Despite that, the object-oriented fad lasted for decades, imposing the programming model that already showed rather fundamental flaws and giving us such technological &ldquo;gems&rdquo; like COM, DCOM, ActiveX, CORBA, Microsoft Foundation Classes, Enterprise Java Beans, and other examples of structural overengineering. And even though most of these &ldquo;inventions&rdquo; are long dead, their effect is still present throughout the industry - in overbloated legacy APIs, untangled dependencies, and fingerprints all over our modern cloud infrastructure.</p>
]]></content></item><item><title>The Smell of Smoke in the Morning</title><link>https://ikhotin.com/posts/2025/07/the-smell-of-smoke-in-the-morning/</link><pubDate>Fri, 04 Jul 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/07/the-smell-of-smoke-in-the-morning/</guid><description>&lt;p>This time, it started much earlier than usual.&lt;/p>
&lt;p>Late afternoon, a chorus of air raid sirens was howling above the city. A harbinger of upcoming drones and missiles. A daily reminder that the war is going on, and you will never catch a break.&lt;/p>
&lt;p>The first waves of buzzing drones started to sneak into the city, followed by hundreds of others — 500+ drones in total, not counting a dozen various missiles.&lt;/p></description><content type="html"><![CDATA[<p>This time, it started much earlier than usual.</p>
<p>Late afternoon, a chorus of air raid sirens was howling above the city. A harbinger of upcoming drones and missiles. A daily reminder that the war is going on, and you will never catch a break.</p>
<p>The first waves of buzzing drones started to sneak into the city, followed by hundreds of others — 500+ drones in total, not counting a dozen various missiles.</p>
<p>The attack lasted for more than 12 hours. I could see bullet traces and puffs of exploding flak shells all over the skies above. Powerful explosions were shaking the city, triggering car alarms all around.</p>
<p>By early morning, when most of it was over, dark smoke was clogging the sky above. Air quality sensors throughout the city turned red. The thick chemical smell prompted me to close all the windows and stay inside until the fires were put out and the wind dispersed the smoke.</p>
<p>Another grim and dusty morning.</p>
]]></content></item><item><title>Burning Skyline</title><link>https://ikhotin.com/posts/2025/06/burning-skyline/</link><pubDate>Tue, 17 Jun 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/06/burning-skyline/</guid><description>&lt;p>The night started with a usual air raid alert, nothing out of the ordinary. Enemy drones were approaching the city. But after the initial strike package, more and more drones were coming in. An annoying buzz of two-cycle engines could be heard throughout the night.&lt;/p>
&lt;p>The sky was sliced with tracing bullets, and firework-like puffs of delay-fuzed shells accompanied by occasional anti-aircraft missiles. Once in a while, a lucky shot would deliver a critical hit, resulting in a bright flash followed by a roaring thunder of an exploding 90kg warhead a few seconds later. When close enough, you can also feel the shockwave hitting your body.&lt;/p></description><content type="html"><![CDATA[<p>The night started with a usual air raid alert, nothing out of the ordinary. Enemy drones were approaching the city. But after the initial strike package, more and more drones were coming in. An annoying buzz of two-cycle engines could be heard throughout the night.</p>
<p>The sky was sliced with tracing bullets, and firework-like puffs of delay-fuzed shells accompanied by occasional anti-aircraft missiles. Once in a while, a lucky shot would deliver a critical hit, resulting in a bright flash followed by a roaring thunder of an exploding 90kg warhead a few seconds later. When close enough, you can also feel the shockwave hitting your body.</p>
<p>Wave after wave, more suicide drones were coming in, overwhelming air defences and striking througout the city. It is a chilling experience to hear a drone suddenly changing the engine pitch while diving in, resulting in a screaming noise followed by an explosion. I guess it is reminiscent of WWII terrifying dive bomber attacks. My grandfather was listening to the screaming Stuka dives on the battlefields of WWII, and now I&rsquo;m listening to Shahed dives 80+ years later. War never changes.</p>
<p>It was even more terrifying to hear dozens of drones diving in and striking one after another. Continuous explosions could be heard for hours.</p>
<p>And then enemy missiles arrived. Hypersonic aeroballistics got intercepted high above the city, sending powerful shockwaves down to earth. Then, the incoming cruise missile where met with a bunch of interceptors. Bright lights of ascending anti-missiles were illuminating my windows, followed by even more explosions.</p>
<p>Most of it was over by dawn, with only occasional explosions of remaining drones.</p>
<p>Ruzzians attacked Kyiv with more than 400 various projectiles - dozens of missiles and hundreds of drones.</p>
<p>One missile hit an apartment building, piercing it to the basement and causing it to collapse and bury inhabitants under the rubble.</p>
<p><img src="/img/2025/2025-06-17.destroyed-apt-building.jpg" alt="collapsed-building"></p>
<p>In my neighbourhood, we got multiple hits with one drone hitting an apartment building (not that different from mine) and killing 3 people.</p>
<p><img src="/img/2025/2025-06-17.drone-hits-apt-building.jpg" alt="collapsed-building"></p>
<p>It is yet another grim morning. When instead of the smell of coffee from a nearby coffee shop, I can smell thick smoke of the burning city, instead of hearing the usual morning city buzz, I&rsquo;m hearing sirens of firetrucks and ambulances rushing through the ash-covered streets and helicopters flying to the nearby lake to scoop more water. And instead of brightly green hills over Dnipro in my window, I see black smoke all over the horizon.</p>
<p>The fires over the city could be registered from space.</p>
<p>When the dust settled and the rubbles were cleared, 28 people were dead and 150+ more wounded.</p>
<p>The daily reality we live in.</p>
]]></content></item><item><title>Pressure Valve Madness Postmortem</title><link>https://ikhotin.com/posts/2025/04/pressure-valve-madness-postmortem/</link><pubDate>Thu, 03 Apr 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/04/pressure-valve-madness-postmortem/</guid><description>&lt;p>&lt;strong>&lt;a href="https://d2jam.com/">Down2Jam&lt;/a>&lt;/strong> is a new entry in the game jams family and I was thrilled to participate in the very first event.
I&amp;rsquo;m always in search of interesting events besides major game jams to experience new formats and look at things from a different angle.&lt;/p>
&lt;p>The theme was &lt;strong>Train&lt;/strong>. After a two-hour-long midnight brainstorm we with the team decided to create a little game about a steam train with a tricky pressure valve you have to operate to keep your boiler from blowing up.&lt;/p></description><content type="html"><![CDATA[<p><strong><a href="https://d2jam.com/">Down2Jam</a></strong> is a new entry in the game jams family and I was thrilled to participate in the very first event.
I&rsquo;m always in search of interesting events besides major game jams to experience new formats and look at things from a different angle.</p>
<p>The theme was <strong>Train</strong>. After a two-hour-long midnight brainstorm we with the team decided to create a little game about a steam train with a tricky pressure valve you have to operate to keep your boiler from blowing up.</p>
<p>The initial design called for a pixelated 2D side view of a steampunk-styled train moving through the desert. At the bottom of the screen, you have a panel with a bunch of controls and gauges showing your speed, boiler temperature and pressure, etc&hellip; The player uses that panel to feed fuel to the train and move. Finally, you arrive at a station where you can do repairs, get resupplies, and trade in various commodities.</p>
<p>It was a good plan, except for being overly optimistic. It looked good on paper but crumbled facing harsh jamming reality. In the end, we barely managed to make a playable prototype - <a href="https://invadium.itch.io/pressure-valve-madness">Pressure Valve Madness</a>.</p>
<h2 id="what-went-right">What went right</h2>
<p>In the end, we got a pretty good steam train simulation. The steam engine model is awesome and actually based on basic thermodynamic principles involved in the actual engine setup. You feed the fuel and the train starts moving. I sketched a sprite for the locomotive, a cart and rotating wheels. We even managed to add a pretty satisfying steam and smoke particles coming out of the boiler. And the final explosion when the boiler blows up is totally epic (even through I used a bunch of premade assets for that).</p>
<h2 id="what-went-wrong">What went wrong</h2>
<p>Besides the moving train, everything else was cut due to the time constraints. Yet another jam that suffered from overoptimistic estimates.</p>
<p>The final hours of the jam were brutal with crunch to make the project into a minimal playable prototype. Completed assets for the parallax background were abandoned, and the steampunk controls ended up as generic buttons and indicators.</p>
<p>Stations and shops were out of the question, but we&rsquo;ve managed to introduce a simple destination meter and a resupply dialog to have some kind of progress. Which was almost pointless, since we didn&rsquo;t have any supply indicators anyways.</p>
<h2 id="dissapointment">Dissapointment</h2>
<p>The whole economic subsystem was supposed to be the meta fun over simple train driving mechanics. It worked so well in <a href="https://invadium.itch.io/300-hearts-for-escape">300 Hearts for Escape</a> and we wanted to build on top of that successful experience and implement an extended version. But in the end, we haven&rsquo;t implemented even a simplified one.</p>
<p>I especially puzzled by the fact, that I hadn&rsquo;t spent much more time back then. In fact, for Down2Jam I&rsquo;ve spent an average number of hours - 33.</p>
<p>For comparison:</p>
<ul>
<li>I spent 36h in a 3-person team on <a href="https://invadium.itch.io/300-hearts-for-escape">300 Hearts for Escape</a> (LD44, Spring 2019).</li>
<li>36h on <a href="https://invadium.itch.io/metro-gang-plus">Metro Gang</a> (LD45, Fall 2019).</li>
<li>36h on <a href="https://invadium.itch.io/station-keeping">Station Keeping</a> (LD46, Spring 2020).</li>
<li>Only 28h in a 3-person team on <a href="https://invadium.itch.io/master-or-ritual">Master of Ritual</a> (LD43, Fall 2018)</li>
<li>46h on Modus Catapultus (LD36, Summer 2016)</li>
<li>And an incredible 57h in a 4-person team on <a href="https://invadium.itch.io/twin-jet-miner">Twin Jet Miner</a> (LD38, 2017)</li>
</ul>
<p>The stat shows a lot of 30+ hours, especially multiple 36h-sprints (which is relatively reasonable for a 3-day jam).</p>
<h2 id="why-failure">Why Failure?</h2>
<p>Once again, we failed to prepare beforehand and spent much time setting up the project and getting familiar (once again) with the framework.</p>
<p>I have to get back to the basics of Collider.JAM project setup, update, and modernize it according to the recent experience. The whole setup should be done form a bunch of pre-made highly compatible patches. Currently, I still have to copy and adapt pieces of code from multiple projects. All these subsystems should
be generalized and made available for easy reuse.</p>
<p>That epiphany allows me to create a roadmap for the next version of <strong>Collider.JAM - War Release 2</strong>. Keep tuned - new updates are coming!</p>
]]></content></item><item><title>Another Failed Jam</title><link>https://ikhotin.com/posts/2025/02/another-failed-jam/</link><pubDate>Fri, 07 Feb 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/02/another-failed-jam/</guid><description>&lt;p>Deadline. No delivery. &lt;em>Another failed jam&lt;/em>.&lt;/p>
&lt;p>It was not going well from the beginning. I decided to participate on the same day the jam started. So I hadn&amp;rsquo;t been able to gather a team and ended up participating solo. Sometimes it works, but it didn&amp;rsquo;t this time.&lt;/p>
&lt;p>Moreover, I started the jam while doing major refactoring in the &lt;strong>&lt;a href="http://collider.land">Collider.JAM&lt;/a>&lt;/strong> event management subsystem. That meant I had to spend some time making the framework functional again.
In the end, I spent about 40 hours over the course of a week working on the game prototype—all for a few working subsystems and no core gameloop.&lt;/p></description><content type="html"><![CDATA[<p>Deadline. No delivery. <em>Another failed jam</em>.</p>
<p>It was not going well from the beginning. I decided to participate on the same day the jam started. So I hadn&rsquo;t been able to gather a team and ended up participating solo. Sometimes it works, but it didn&rsquo;t this time.</p>
<p>Moreover, I started the jam while doing major refactoring in the <strong><a href="http://collider.land">Collider.JAM</a></strong> event management subsystem. That meant I had to spend some time making the framework functional again.
In the end, I spent about 40 hours over the course of a week working on the game prototype—all for a few working subsystems and no core gameloop.</p>
<p>I&rsquo;d set overambitious goals, but failed to crystallize the vision soon enough <em>to switch to the jam mode and deliver</em>. I missed the initial momentum so necessary for any jam to succeed. And then just observed as the jam deadline was creeping in with no velocity behind me to meet the ambitious goals.</p>
<p>Inevitably, I&rsquo;ve got another <em>failed jam</em>.</p>
<p>This failure closely resembles my failed <em>Ludum Dare 33</em> in August 2015. Even the themes were very alike - <em>&ldquo;You are the weapon&rdquo;</em> for this one and <em>&ldquo;You are the monster&rdquo;</em> for LD33. Both ended very similarly - in spectacular failures with a few working systems and no gameplay in sight.</p>
<p>But the <em>LD33</em> failure in the end turned out to be a huge success, since that triggered exploration of new tech horizons and eventually led to the creation of <a href="http://collider.land">Collider.JAM</a>.</p>
<p>Later, in <em>Ludum Dare 38</em> on April 2017, I participated with a team and we already used <em>a jam starter pack</em> that later evolved into a full-featured framework for rapid prototyping and jamming.</p>
<p>I want this failure to be the same - a catalyst for positive changes in <strong>Collider.JAM</strong>. By analysing the time wasters, I can optimize the development pipeline so it would be even easier to start next time.</p>
<p>I think it was a slow bootstrap that caused me to lose the initial momentum. The bootstrapping should be straightforward and fun. It should establish all generic systems with little adaptation efforts. Don&rsquo;t go into a jam creating unique systems unless you have a whole team of good developers on board.</p>
<p>That experience hints at the upcoming optimizations in <strong>Collider.JAM</strong> - all these subsystems must be delivered as ready-to-use, dropped-in patches, working with little-to-no customization. That follows the general <strong>Collider.JAM</strong> philosophy when we prefer to provide reasonable defaults out of the box.</p>
<p>So despite the obvious failure, I am still full of ideas on what to do next. The upcoming <a href="https://github.com/invadium/collider.jam">release of Collider.JAM</a> will be more usable than ever.</p>
]]></content></item><item><title>Yet Another Ballistic Strike on Kyiv</title><link>https://ikhotin.com/posts/2025/01/yet-another-ballistic-strike-on-kyiv/</link><pubDate>Sat, 18 Jan 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/01/yet-another-ballistic-strike-on-kyiv/</guid><description>&lt;p>It was a typical night in Ukraine. Long-range drones were launched in waves after midnight. After 4 AM we could hear shooting and explosions somewhere in our neighborhood - these were anti-aircraft fireteams trying to shoot down drones coming into the city from our direction. Nothing special.
At 6 AM, all drones in Kyiv&amp;rsquo;s vicinity were eliminated and the air raid alert was over. Just a few minutes later we heard a series of explosions (too powerful to be drones) and air raid sirens triggered almost simultaneously with the first blast. Russians used ballistic missiles on Kyiv once again.&lt;/p></description><content type="html"><![CDATA[<p>It was a typical night in Ukraine. Long-range drones were launched in waves after midnight. After 4 AM we could hear shooting and explosions somewhere in our neighborhood - these were anti-aircraft fireteams trying to shoot down drones coming into the city from our direction. Nothing special.
At 6 AM, all drones in Kyiv&rsquo;s vicinity were eliminated and the air raid alert was over. Just a few minutes later we heard a series of explosions (too powerful to be drones) and air raid sirens triggered almost simultaneously with the first blast. Russians used ballistic missiles on Kyiv once again.</p>
<p>It left 3 people dead. Even though the missiles were intercepted and it doesn&rsquo;t look like the warheads have detonated, the huge kinetic energy of several tons of falling debris caused a lot of devastation.</p>
<p>I had a terrible headache the whole day, the same is true for my wife. So even though physically we were not hurt, these attacks are taking their toll emotionally.</p>
<p>Another bad day in Kyiv.</p>
]]></content></item><item><title>Input Subsystem Redesign</title><link>https://ikhotin.com/posts/2025/01/input-subsystem-redesign/</link><pubDate>Sat, 04 Jan 2025 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2025/01/input-subsystem-redesign/</guid><description>&lt;p>&lt;strong>Any game is driven by events.&lt;/strong> And the most foundational ones are related to controls. Player input is super-important since it steers the simulation. That is why the effort put into the input subsystem design pays off handsomely.&lt;/p>
&lt;h2 id="the-origin">The Origin&lt;/h2>
&lt;p>&lt;strong>Collider.JAM&lt;/strong> started with a very basic input system. All input events are captured by functions in &lt;code>/trap&lt;/code>. So &lt;code>/trap/keyUp(e)&lt;/code> captures all key up events, &lt;code>/trap/mouseMove(e)&lt;/code> - all mouse movements. Or maybe you want to capture an R keypress by creating &lt;code>trap/rDown(e)&lt;/code>.
It is simple, straightforward, and, more importantly, follows Collider.JAM opinionated conventions for names and placements.&lt;/p></description><content type="html"><![CDATA[<p><strong>Any game is driven by events.</strong> And the most foundational ones are related to controls. Player input is super-important since it steers the simulation. That is why the effort put into the input subsystem design pays off handsomely.</p>
<h2 id="the-origin">The Origin</h2>
<p><strong>Collider.JAM</strong> started with a very basic input system. All input events are captured  by functions in <code>/trap</code>. So <code>/trap/keyUp(e)</code> captures all key up events, <code>/trap/mouseMove(e)</code> - all mouse movements. Or maybe you want to capture an R keypress by creating <code>trap/rDown(e)</code>.
It is simple, straightforward, and, more importantly, follows Collider.JAM opinionated conventions for names and placements.</p>
<p>Basically, you establish input handling by dropping a few <code>.js</code> files in the <code>/trap</code> folder. Very good for a simple prototype. But not good enough for more complex scenarios.</p>
<h2 id="handling-controllers">Handling Controllers</h2>
<p>To address challenges of bigger games I&rsquo;ve created a controller subsystem that builds upon the existing Collider.JAM foundation and handles more sophisticated cases, including input remapping and gamepads.</p>
<p>That system included a concept of <em>&ldquo;actions&rdquo;</em> and a way to map incoming gamepad/keyboard events into those actions. Then, there is a way to <em>&ldquo;bind&rdquo;</em> controls to a particular entity in the <code>/lab</code>. All you have to do is to implement an <code>act(action)</code> function with a switch to react to each particular event.</p>
<h2 id="the-limitations">The Limitations</h2>
<p>This system worked fine, but many games later I discovered its limitations. It is not easy to customize the mappings to gamepads (a bit easier for the keyboard though). Also, the idea of processing actions as integers turned out to be somehow limiting and in some places confusing. To improve readability, I always introduced global constants (e.g. UP = 1, LEFT = 2, DOWN = 3&hellip;). It is cumbersome and not flexible. Plus, there are cases when you would prefer to use human-readable strings for actions instead of constant numbers.</p>
<p>For a long time, I hesitated between two approaches - what must my actions be, constant-defined numbers like <code>LEFT=2</code> or human-readable string literals like &ldquo;left&rdquo;?</p>
<p>Recently, I finally realized that the best approach is to merge those two in an input event object. That would allow us to use numeric values where convenient and string ones where clarity is the priority. Also, we can keep additional metadata there, like timings and the origin event objects.</p>
<p>So it is time to refactor the controller handling for <strong>Collider.JAM</strong>!</p>
<h2 id="the-plan">The Plan</h2>
<p>We will introduce a new binding system with human-readable labels and the ability to remap. We will represent actions as objects. We will design for more complex scenarios, like the ability to store and restore entity bindings when switching between states.</p>
<p>And finally, the whole controller subsystem will be available as a collider patch within a standard <strong>Collider.JAM</strong> package.</p>
]]></content></item><item><title>All Kinds of Air Raids</title><link>https://ikhotin.com/posts/2024/07/all-kinds-of-air-raids/</link><pubDate>Wed, 31 Jul 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/07/all-kinds-of-air-raids/</guid><description>&lt;p>&lt;em>Air raids are different.&lt;/em>&lt;/p>
&lt;p>Ballistic missile attacks are sudden, swift, and brutal. No compromise, no remorse. Ballistic missiles are fast. Usually, you have only a minute or two between the alert and the incoming.&lt;/p>
&lt;p>You don&amp;rsquo;t have time to look for a shelter. If caught outside, just hide inside the nearest building. You are in luck if there is a subsurface facility nearby - an underground pedestrian crossing, an underground parking lot, or a subway. The best of them, of course, is a subway, designed in the Cold War to be a nuclear shelter.&lt;/p></description><content type="html"><![CDATA[<p><em>Air raids are different.</em></p>
<p>Ballistic missile attacks are sudden, swift, and brutal. No compromise, no remorse. Ballistic missiles are fast. Usually, you have only a minute or two between the alert and the incoming.</p>
<p>You don&rsquo;t have time to look for a shelter. If caught outside, just hide inside the nearest building. You are in luck if there is a subsurface facility nearby - an underground pedestrian crossing, an underground parking lot, or a subway. The best of them, of course, is a subway, designed in the Cold War to be a nuclear shelter.</p>
<p>If the alarm catches you at home or in an office, it is better to stay inside. It is the best option since the strike might happen while you are outside still looking for shelter. Actually, we had fatalities in the city when the falling debris of an intercepted missile killed someone who was looking for shelter. So it is better to stay inside within the location you are currently in and look for the most reinforced place away from windows. Try to have at least two walls between you and the outside. If your building has an underground parking lot, it is a good idea to move there ASAP.</p>
<p>It can also be that a ballistic attack caught you in transit. The worst-case scenario I can think of is when you are stuck in traffic on one of the bridges over the river. There is nothing you can do then but hope that this strike is not targeting this particular bridge.</p>
<p>Cruise missiles are different. Russians launch them from standoff distances way inside their territory to keep strategic bombers away from danger. Often somewhere over the Caspian Sea. It takes at least an hour for a relatively slow subsonic missile to reach Ukraine. When the launch is detected, you have plenty of time to plan your shelter arrangements.</p>
<p>Drones are the slowest of the explosives delivery bunch. So the drone attacks are the most exhausting ones.</p>
<p>When the city is hit by ballistics, you hear the air raid alerts, then explosions in a few minutes. You still have to wait until the air raid alert is over as a safeguard for additional attack waves.</p>
<p>Windows are shaking, and adrenaline is spiking, but after the burst of explosions, it usually is over pretty soon. If you hear ballistic missiles hitting or being intercepted, that means these are not meant for you. You will never hear a ballistic missile hitting you since they are supersonic. First comes the explosion, then the sound (though there are still very dangerous debris and shrapnel afterward).</p>
<p>Drones are a different beast. Ruzzians launch Iranian Shaheds in batches late in the evening and wave after wave, these drones are flying and circling all over Ukraine for hours.</p>
<p>Last night, the initial air raid alert was declared at 10 PM. That means the drones are closing in on Kyiv. And they continue to come in multiple waves during the night. Almost 100 drones in total, 30+ of them targeting Kyiv. Each time another pack of drones enters Kyiv we have an additional &ldquo;Increased Air Threat&rdquo; alert. We had like 11 or 12 of these throughout the night mixed with shooting and explosions when these drones were intercepted here and there.</p>
<p>No drone passed through the air defense deep into the city last night, but bad sleep for millions of Ukrainians was ensured. Another attack is repealed. And once again I&rsquo;m consuming copious amounts of coffee in the morning to compensate for the sleepless night.</p>
<p>Just another sleepy day.</p>
]]></content></item><item><title>Missilophobia</title><link>https://ikhotin.com/posts/2024/07/missilophobia/</link><pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/07/missilophobia/</guid><description>&lt;p>The inevitable thing in a war is that my son is terrified of thunder now. It sounds somewhat similar to missile strikes, and each time we have a thunderstorm, he runs into a corridor away from windows to seek shelter. But I don&amp;rsquo;t think it is brontophobia - the fear of thunder. Rather, it is a case of missilophobia.&lt;/p>
&lt;p>Today, our side of the city didn&amp;rsquo;t get much rain. It happens sometimes when you live on a big river - one bank could have a different weather from the other.&lt;/p></description><content type="html"><![CDATA[<p>The inevitable thing in a war is that my son is terrified of thunder now. It sounds somewhat similar to missile strikes, and each time we have a thunderstorm, he runs into a corridor away from windows to seek shelter. But I don&rsquo;t think it is brontophobia - the fear of thunder. Rather, it is a case of missilophobia.</p>
<p>Today, our side of the city didn&rsquo;t get much rain. It happens sometimes when you live on a big river - one bank could have a different weather from the other.</p>
<p><img src="/img/2024/rain-over-dnipro.jpg" alt="Rain over Drinpro"></p>
<p>So it rained on the other side. We got a lot of thunder, though. Heavy, powerful rumbles could be heard for hours.</p>
<p>Closer to midnight, the thunder was long gone, but it was everything, but quiet. Ruzzian drones were closing in on Kyiv from the east - seems like I&rsquo;m on a vector of attack&hellip; Again.</p>
<p>Then, there was an explosion. Most certainly caused by an anti-aircraft missile intercepting a nearby drone. It was so forceful that I jumped out of my chair. The blast was followed by smaller prolonged secondary explosions and sounds of falling debris.</p>
<p>It was a stealthy drone that managed to penetrate the city undetected and was engaged when already inside the city limits.</p>
<p>Well, I can confidently say that the sound is different. There was no doubt in my mind, even for a second, that the explosion was caused by thunder.</p>
<p>We were lucky this evening, and nobody was hurt by the falling debris. So, it&rsquo;s a good day after all.</p>
]]></content></item><item><title>Bloody Monday</title><link>https://ikhotin.com/posts/2024/07/bloody-monday/</link><pubDate>Mon, 08 Jul 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/07/bloody-monday/</guid><description>&lt;p>Today marks the bloodiest missile strike on Kyiv so far this year.&lt;/p>
&lt;p>You never know when the next attack is coming.&lt;/p>
&lt;p>It was a typical Monday morning. The city was buzzing with activity. There was a limited drone attack during the night, but it was long over.&lt;/p>
&lt;p>Suddenly, all hell breaks loose. 40+ missiles from all directions converged on Kyiv almost simultaneously.&lt;/p>
&lt;p>The combined attack included various types of missiles. Ship and submarine-launched Kalibr cruise missiles, Kh-101 cruise missiles launched by strategic aviation, land-based ballistic Iskanders, air-launched aeroballistic Kinzhals, and even a hypersonic Zircon.&lt;/p></description><content type="html"><![CDATA[<p>Today marks the bloodiest missile strike on Kyiv so far this year.</p>
<p>You never know when the next attack is coming.</p>
<p>It was a typical Monday morning. The city was buzzing with activity. There was a limited drone attack during the night, but it was long over.</p>
<p>Suddenly, all hell breaks loose. 40+ missiles from all directions converged on Kyiv almost simultaneously.</p>
<p>The combined attack included various types of missiles. Ship and submarine-launched Kalibr cruise missiles, Kh-101 cruise missiles launched by strategic aviation, land-based ballistic Iskanders, air-launched aeroballistic Kinzhals, and even a hypersonic Zircon.</p>
<p>Explosions shook my apartment building. I briefly glanced outside to see a couple of anti-aircraft missiles rising to the sky to intercept another ballistic threat.</p>
<p>When the explosions were over, I saw black smoke over the city. This Monday is harder than usual.</p>
<p>Today, a ruzzian missile hit the biggest child hospital in Ukraine. The surfaced video clearly shows a ruzzian Kh-101 missile flying unintercepted right into one of the hospital complex buildings. Which means it hit exactly where it was programmed to hit. So there is actually a person who entered the coordinates of a child&rsquo;s hospital into the missile computer.</p>
<p>Not only that, but a couple of hours later, the next wave of missiles hit another part of the city. One missile hit a reproductive clinic, killing 9 people inside, including patients and medical personnel. This definitely demonstrates that strikes on medical facilities are not accidental, but deliberate.</p>
<p>Other parts of the city were also hit. Another missile blew up a section of an apartment building. So now, emergency services and volunteers are cleaning up the rubble of the collapsed structure, looking for survivors.</p>
<p>Today, I am more pessimistic than ever. A daylight strike in the rush hour to increase the number of victims shows yet another escalation from the ruzzian side. The end of the war is nowhere to be seen and it just spreads and becomes more violent.</p>
]]></content></item><item><title>Explosive Wake-Up</title><link>https://ikhotin.com/posts/2024/05/explosive-wake-up/</link><pubDate>Fri, 31 May 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/05/explosive-wake-up/</guid><description>&lt;p>&lt;strong>Boom!&lt;/strong> The explosion was so loud that I heard window frames pressed in with a cracking sound. I jumped out of bed,
my heart pounding fast and my mouth swearing.
A thick wall facing my office offers some protection,
so I moved away from the windows closer to that wall,
expecting more explosions to follow.
But it was all for now. It is 5 am and Ukrainian air defense just intercepted a &lt;em>9M727 Iskander-K cruise missile&lt;/em> low over southern parts of Kyiv.&lt;/p></description><content type="html"><![CDATA[<p><strong>Boom!</strong> The explosion was so loud that I heard window frames pressed in with a cracking sound. I jumped out of bed,
my heart pounding fast and my mouth swearing.
A thick wall facing my office offers some protection,
so I moved away from the windows closer to that wall,
expecting more explosions to follow.
But it was all for now. It is 5 am and Ukrainian air defense just intercepted a <em>9M727 Iskander-K cruise missile</em> low over southern parts of Kyiv.</p>
<p>When an air raid alert triggered on my phone at 4:50 AM, I kept sleeping.
I also ignored an increased thread alert buzzed at 4:52 AM warning about an imminent strike.</p>
<p>But you can&rsquo;t ignore an explosion. I was instantly up and fully awake. Talking about a super fast and decisive alarm clock. You can&rsquo;t snooze this one!
There is no need for a knocker-up person when you have
a crazy neighbor regularly launching missiles at you early in the morning.</p>
<p><em>Everything is fine.</em> The missile is intercepted, the damage is minimal and nobody has died from this attack.</p>
<p><em>A thundering beginning of a new day.</em></p>
]]></content></item><item><title>Collider.JAM Development Setup</title><link>https://ikhotin.com/posts/2024/05/collider.jam-development-setup/</link><pubDate>Thu, 30 May 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/05/collider.jam-development-setup/</guid><description>&lt;p>You can use &lt;a href="http://collider.land">Collider.JAM&lt;/a> by simply installing &lt;code>collider.jam&lt;/code> npm package globally with &lt;code>npm install -g collider.jam&lt;/code>.
This command installs the latest stable Collider.JAM release and gives you
the &lt;code>jam&lt;/code> tool to initialize and launch &lt;strong>Collider.JAM&lt;/strong> mixes.
This is the simplest way to use Collider.JAM and it often covers
all your development needs.&lt;/p>
&lt;p>But in my case, I need something more intricate.
Since I&amp;rsquo;m not only using Collider.JAM, but also &lt;em>developing it&lt;/em>,
I need an installation working right from git repositories deployed locally instead of using pre-packaged remote snapshots.
&lt;em>That way I can introduce changes and test them right away.&lt;/em>&lt;/p></description><content type="html"><![CDATA[<p>You can use <a href="http://collider.land">Collider.JAM</a> by simply installing <code>collider.jam</code> npm package globally with <code>npm install -g collider.jam</code>.
This command installs the latest stable Collider.JAM release and gives you
the <code>jam</code> tool to initialize and launch <strong>Collider.JAM</strong> mixes.
This is the simplest way to use Collider.JAM and it often covers
all your development needs.</p>
<p>But in my case, I need something more intricate.
Since I&rsquo;m not only using Collider.JAM, but also <em>developing it</em>,
I need an installation working right from git repositories deployed locally instead of using pre-packaged remote snapshots.
<em>That way I can introduce changes and test them right away.</em></p>
<p>One also could benefit from that type of installation in complex
project requiring some framework customizations.
Just fork a package you want to customize and link it with
other parts of the framework.</p>
<p><em>Here are the necessary steps to do that.</em></p>
<h3 id="1-create-framework-folder">1. Create Framework Folder</h3>
<p>Select an appropriate location and create a folder for Collider.JAM
packages. I find it convenient to keep all framework components
in a separate folder:</p>
<pre tabindex="0"><code>mkdir jam
</code></pre><h3 id="2-clone-colliderjam-repos">2. Clone Collider.JAM Repos</h3>
<p><a href="http://collider.land">Collider.JAM</a>
consists of 4 major packages you need to install:
<a href="https://github.com/invadium/collider.jam">collider.jam</a>,
<a href="https://github.com/invadium/collider.mix">collider.mix</a>,
<a href="https://github.com/invadium/collider-dev.mix">collider-dev.mix</a>,
<a href="https://github.com/invadium/collider-boot.mix">collider-boot.mix</a>.</p>
<pre tabindex="0"><code>cd jam
git clone git@github.com:invadium/collider.jam.git
git clone git@github.com:invadium/collider.mix.git
git clone git@github.com:invadium/collider-dev.mix.git
git clone git@github.com:invadium/collider-boot.mix.git
</code></pre><h3 id="3-link-packages-globally">3. Link Packages Globally</h3>
<p>We definitely can install collider.jam package from local
git repository globally by running <code>npm install -g</code> from
the <code>collider.jam</code> folder. But when you introduce any changes
to <code>collider.jam</code> it must be reinstalled for changes
to take place. Even worse, any changes to submodules
(like <code>collider.mix</code> or <code>collider-dev.mix</code>) are going
to be ignored, since <code>collider.jam</code> package uses their
snapshots from remote repos.</p>
<p>To fix this we need to link those packages with local repo deployments. Linking is a two-step process.</p>
<p>First, we create global links for each locally deployed component:</p>
<pre tabindex="0"><code>cd collider.jam
sudo npm link
cd ../collider.mix
sudo npm link
cd ../collider-dev.mix
sudo npm link
cd ../collider-boot.mix
sudo npm link
cd ..
</code></pre><p>This links the global npm packages to the local repos.</p>
<h3 id="local-link">Local Link</h3>
<p>The last step is to link those package dependencies locally.
When you run <code>npm install</code> or <code>npm update</code> npm installs
or updates package snapshots in <code>./node_modules</code> folder.</p>
<p>We need to patch <code>./node_modules</code> so it would contain the links
to actual local repos instead of remote snapshots.</p>
<p>Only the packages with other framework dependencies need to be linked - <code>collider-dev.mix</code> and <code>collider.jam</code>.</p>
<pre tabindex="0"><code>cd jam/collider-dev.mix
npm install
npm link collider.mix
cd ..

cd collider.jam
npm install
npm link collider.mix collider-dev.mix collider-boot.mix
</code></pre><p>The <code>link &lt;module-name&gt;</code> command creates a link to package deployment in <code>./node_modules</code>.</p>
<p>Note, that these links are going to be wiped next time you run
<code>npm install</code> or <code>npm update</code>.
So this linking process must be repeated after each install or update.</p>
<p>Since this deployment is very peculiar and necessary only when
developing or modifying
<a href="http://collider.land">Collider.JAM</a>, there is currently
no command in <code>jam</code> to help you with that.
All steps need to be performed manually.</p>
<p><em>You might want to create a script to automate this.</em></p>
]]></content></item><item><title>Blackouts</title><link>https://ikhotin.com/posts/2024/05/blackouts/</link><pubDate>Wed, 15 May 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/05/blackouts/</guid><description>&lt;p>It&amp;rsquo;s started again. Early in the morning power went out. We got another blackout — the likes we&amp;rsquo;d never seen since February 2023.&lt;/p>
&lt;p>Recent Russian missile strikes on hydroelectric dams and thermal power plants left 8GWt whole in the Ukrainian power grid and it was just a matter of time before the system became unbalanced. Kyiv was luckier than others for a few weeks, but it looks like that luck ran out.&lt;/p></description><content type="html"><![CDATA[<p>It&rsquo;s started again. Early in the morning power went out. We got another blackout — the likes we&rsquo;d never seen since February 2023.</p>
<p>Recent Russian missile strikes on hydroelectric dams and thermal power plants left 8GWt whole in the Ukrainian power grid and it was just a matter of time before the system became unbalanced. Kyiv was luckier than others for a few weeks, but it looks like that luck ran out.</p>
<p>So now I&rsquo;m getting to the old routine of keeping my laptops and power banks charged in addition to warm tea, water, and some food in thermal bottles.</p>
<p>I&rsquo;m one of the lucky souls who only need a laptop and the Internet for work. Some businesses will suffer more, especially the ones requiring uninterrupted power supply.</p>
<p>But even with electricity gone, the city lives on. I hear the buzz of portable power generators. Cafes in the area were prepared, meaning I could still enjoy my morning coffee and croissant.</p>
<p>The war continues but so is life.</p>
]]></content></item><item><title>Zircon Strike</title><link>https://ikhotin.com/posts/2024/03/zircon-strike/</link><pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2024/03/zircon-strike/</guid><description>&lt;p>Today explosions started before I heard the air raid alert. Powerful shockwaves shook my apartment causing doors and windows to vibrate and bend with cracking sound.&lt;/p>
&lt;p>It looks like Kyiv was attacked with hypersonic 3M22 Zircon missiles from the occupied Crimea. They fly so fast that there is very little time to react.&lt;/p>
&lt;p>We moved to the corridor as fast as possible since there was no time to get to the bomb shelter. Here, in Kyiv, we had cases of people killed by falling debris on the way to a shelter, so sometimes it is just safer to stay inside away from windows.&lt;/p></description><content type="html"><![CDATA[<p>Today explosions started before I heard the air raid alert. Powerful shockwaves shook my apartment causing doors and windows to vibrate and bend with cracking sound.</p>
<p>It looks like Kyiv was attacked with hypersonic 3M22 Zircon missiles from the occupied Crimea. They fly so fast that there is very little time to react.</p>
<p>We moved to the corridor as fast as possible since there was no time to get to the bomb shelter. Here, in Kyiv, we had cases of people killed by falling debris on the way to a shelter, so sometimes it is just safer to stay inside away from windows.</p>
<p>One of the missiles hit another part of the city destroying a little two-story building, part of a university campus. Usually used for fitness or dance classes for teens and kids, the building luckily was empty at the moment of the strike. So we are extremely lucky nobody got killed&hellip; This time.</p>
<p>Just another day in Ukraine.</p>
]]></content></item><item><title>Collider.JAM DR10</title><link>https://ikhotin.com/posts/2021/04/collider.jam-dr10/</link><pubDate>Wed, 07 Apr 2021 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2021/04/collider.jam-dr10/</guid><description>&lt;p>I&amp;rsquo;m happy to announce &lt;strong>Collider.JAM Development Release 10&lt;/strong>.&lt;/p>
&lt;p>It is a massive release baked for almost 4 months.
The &lt;a href="https://github.com/invadium/collider.jam/blob/ver0.0.11-dr10/CHANGELOG">changelog&lt;/a>
alone is bigger than any of the previous ones.&lt;/p>
&lt;p>A lot of effort this time went to simplify project bootstrap.
You can now use &lt;code>jam init ls&lt;/code> to list all available samples:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mkdir next.mix
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd next.mix
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>jam init ls
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The last command will scan installed modules and list all available samples.
By the way, &lt;code>jam init list&lt;/code> or &lt;code>jam init help&lt;/code> would also work just fine.
I&amp;rsquo;m trying to make the &lt;em>cli&lt;/em> as user-friendly and forgiving as possible :)&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;m happy to announce <strong>Collider.JAM Development Release 10</strong>.</p>
<p>It is a massive release baked for almost 4 months.
The <a href="https://github.com/invadium/collider.jam/blob/ver0.0.11-dr10/CHANGELOG">changelog</a>
alone is bigger than any of the previous ones.</p>
<p>A lot of effort this time went to simplify project bootstrap.
You can now use <code>jam init ls</code> to list all available samples:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir next.mix
</span></span><span style="display:flex;"><span>cd next.mix
</span></span><span style="display:flex;"><span>jam init ls
</span></span></code></pre></div><p>The last command will scan installed modules and list all available samples.
By the way, <code>jam init list</code> or <code>jam init help</code> would also work just fine.
I&rsquo;m trying to make the <em>cli</em> as user-friendly and forgiving as possible :)</p>
<p>There is going to be one new interesting sample in the list:</p>
<pre tabindex="0"><code>* planets - bouncing planets sample
</code></pre><p>Bootstrap the project with:</p>
<pre tabindex="0"><code>jam init planets
</code></pre><p>Collider.JAM will generate a <em>package.json</em> and other artifacts.</p>
<p>Now you can run the project:</p>
<pre tabindex="0"><code>jam play
</code></pre><p>A browser should open with a flying planet.
Click on the screen to spawn more planets.</p>
<p>From the features included in DR10
the most interesting is color manipulation.</p>
<p>Now it is easy to transform string color descriptors back to
rgb or hsl representations and also manipulate colors with
lighten(), saturate(), and shiftHue().</p>
<p>It can be used to simulate light effects and manipulate sprite colors
(e.g. colorize multiple teams from a single source sprite).</p>
<p>There are also helpful utilities included in this version.
Like <code>obj.toData()</code> to simplify JSON object serialization
and <code>lib.array.prev()</code> and <code>lib.array.next()</code>
to walk over the elements of an array.</p>
<p>There are some compatibility-breaking changes in the APIs
(like _sizable flag was renamed to _rectangular),
but it mostly affects Collider.JAM internals like HUD subsystem
and shouldn&rsquo;t break client code in most of the cases.</p>
<p>The APIs look stable and ready to migrate to the stable Alpha-release branches.</p>
]]></content></item><item><title>Collider.JAM Spring 2021 Roadmap</title><link>https://ikhotin.com/posts/2021/03/collider.jam-spring-2021-roadmap/</link><pubDate>Sun, 21 Mar 2021 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2021/03/collider.jam-spring-2021-roadmap/</guid><description>&lt;p>We are a few steps from &lt;strong>Alpha Release 1&lt;/strong>.&lt;/p>
&lt;p>&lt;strong>Development Release 10&lt;/strong> is going to be shipped soon.
Then, DR 11 and 12 will follow,
and we might finally be ready to ship the first Alpha.&lt;/p>
&lt;p>Spring is traditionally a jam season.
And since it is Collider.JAM,
all major releases are usually shipped around these jams :)&lt;/p>
&lt;p>Themes and limitations are always different,
so each jam provides a unique testing playground
for framework features and development approach.&lt;/p></description><content type="html"><![CDATA[<p>We are a few steps from <strong>Alpha Release 1</strong>.</p>
<p><strong>Development Release 10</strong> is going to be shipped soon.
Then, DR 11 and 12 will follow,
and we might finally be ready to ship the first Alpha.</p>
<p>Spring is traditionally a jam season.
And since it is Collider.JAM,
all major releases are usually shipped around these jams :)</p>
<p>Themes and limitations are always different,
so each jam provides a unique testing playground
for framework features and development approach.</p>
<p>I&rsquo;ve started the season with <a href="https://center42.tech/hyper-casual-jam/2021">Going Hyper Winter 2021</a>
and my third <a href="https://itch.io/jam/7drl-challenge-2021">7DRL Challenge</a>.
Each deserves a separate post-mortem and each challenged Collider.JAM in new and unexpected ways.</p>
<p>There are hardly any major features, but many small changes
making the framework usage more pleasant and consistent.</p>
<p>So now I&rsquo;m sharpening my tools for the upcoming <a href="https://ldjam.com/">Ludum Dare 48</a> in late April. It is my next milestone.
There is definitely going to be another Collider.JAM release with
a bunch of cool features!</p>
]]></content></item><item><title>Green Eyes</title><link>https://ikhotin.com/posts/2020/12/green-eyes/</link><pubDate>Sun, 20 Dec 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/12/green-eyes/</guid><description>&lt;p>Eyes watching a mouse cursor have being a good GUI demo app
since the early versions of X-Window.
It shows how to work with color, draw simple shapes
and handle mouse coordinates.&lt;/p>
&lt;p>Let&amp;rsquo;s see how easy it is to build
a similar app with &lt;a href="http://collider.land">Collider.JAM&lt;/a>
and JavaScript.&lt;/p>
&lt;p>&lt;img src="https://ikhotin.com/img/2020/eyes-1.png" alt="Eyes">&lt;/p>
&lt;p>And let&amp;rsquo;s also extend the original concept by adding
the ability to create additional eyes on the mouse click.
There was no way to do that in the original
X-Window version, but we can do it,
since we have the whole canvas at our disposal.&lt;/p></description><content type="html"><![CDATA[<p>Eyes watching a mouse cursor have being a good GUI demo app
since the early versions of X-Window.
It shows how to work with color, draw simple shapes
and handle mouse coordinates.</p>
<p>Let&rsquo;s see how easy it is to build
a similar app with <a href="http://collider.land">Collider.JAM</a>
and JavaScript.</p>
<p><img src="/img/2020/eyes-1.png" alt="Eyes"></p>
<p>And let&rsquo;s also extend the original concept by adding
the ability to create additional eyes on the mouse click.
There was no way to do that in the original
X-Window version, but we can do it,
since we have the whole canvas at our disposal.</p>
<p><img src="/img/2020/xeyes.png" alt="xeyes"></p>
<hr>
<h2 id="mod-sketch-project">.mod sketch project</h2>
<p>Let&rsquo;s create a Collider.JAM <strong>.mod</strong> project
and <code>dna/eye.js</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir eyes.mod
</span></span><span style="display:flex;"><span>cd eyes.mod
</span></span><span style="display:flex;"><span>mkdir dna
</span></span><span style="display:flex;"><span>touch dna/eye.js
</span></span></code></pre></div><h2 id="defaults">defaults</h2>
<p>First, we need to define eye defaults in <code>dna/eyes.js</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// dna/eyes.js
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">defaults</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">x</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">5</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">y</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">ry</span>(.<span style="color:#ae81ff">5</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">hr</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">02</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">vr</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">03</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">color</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">hsl</span>(.<span style="color:#ae81ff">1</span>, .<span style="color:#ae81ff">9</span>, .<span style="color:#ae81ff">9</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">iris</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">size</span><span style="color:#f92672">:</span> .<span style="color:#ae81ff">5</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">shift</span><span style="color:#f92672">:</span> .<span style="color:#ae81ff">4</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">color</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">hsl</span>(.<span style="color:#ae81ff">42</span>, .<span style="color:#ae81ff">4</span>, .<span style="color:#ae81ff">5</span>),
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">pupil</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">size</span><span style="color:#f92672">:</span> .<span style="color:#ae81ff">2</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">shift</span><span style="color:#f92672">:</span> .<span style="color:#ae81ff">55</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">color</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">hsl</span>(.<span style="color:#ae81ff">05</span>, .<span style="color:#ae81ff">3</span>, .<span style="color:#ae81ff">1</span>),
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This object contains the values we use
to initialize a newly constructed eye instance.</p>
<p>The properties <code>x</code> and <code>y</code> set the eye
center position, <code>hr</code> and <code>vr</code> -
horizontal and vertical radiuses for the eye ellipse.
The eye <code>color</code> is also defined here.</p>
<p>Functions <code>rx()</code> and <code>ry()</code> calculate
relative sizes to screen width and height.
So <code>rx(.5)</code> means the half of the screen width
and <code>ry(1)</code> means the full-screen height.</p>
<p>An eye has two internal parts - iris and pupil.
Each defined by its own property object
that determines the size (relative
to the eye horizontal radius), color, and shift.
The shift is a distance to move the iris or pupil
towards the mouse cursor.
It is also defined relative to the <code>hr</code> value.</p>
<h2 id="onclone">onClone()</h2>
<p>We are going to define <code>eye</code> as a simple prototype
instead of a <em>constructor</em> or a <em>factory</em>.
It means the defined object will be used as
a prototype to clone new instances.
This process doesn&rsquo;t create a traditional JavaScript
prototype chain, rather produces a fully independent object.</p>
<p>The <code>onClone()</code> function is used in <strong>Collider.JAM</strong>
to initialize a cloned object after construction.
Any fancy actions required to setup the object
can be performed here.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> <span style="color:#a6e22e">id</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">onClone</span>(<span style="color:#a6e22e">settings</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;eye&#39;</span> <span style="color:#f92672">+</span> (<span style="color:#f92672">++</span><span style="color:#a6e22e">id</span>) <span style="color:#75715e">// assign a unique name
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">augment</span>(<span style="color:#66d9ef">this</span>, <span style="color:#a6e22e">defaults</span>, <span style="color:#a6e22e">settings</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The function assigns a unique name
like <code>eye1</code>, <code>eye2</code> etc&hellip;
Next, it augments the cloned object
with <em>default</em> and <em>spawn</em> settings.</p>
<h2 id="draw">draw()</h2>
<p>The drawing procedure is the most complex one
in this app.
But the meaning of each individual command
is pretty straightforward.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">draw</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// declare local shortcuts to simplify calculations
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">const</span> { <span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">hr</span>, <span style="color:#a6e22e">vr</span>, <span style="color:#a6e22e">iris</span>, <span style="color:#a6e22e">pupil</span> } <span style="color:#f92672">=</span> <span style="color:#66d9ef">this</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// eye
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">fill</span>(<span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">color</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">ellipse</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">hr</span>, <span style="color:#a6e22e">vr</span>)
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// calculate direction of the mouse cursor
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">dir</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">bearing</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">y</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">d</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">dist</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">y</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// iris
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">fill</span>(<span style="color:#a6e22e">iris</span>.<span style="color:#a6e22e">color</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">ishift</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">hr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">iris</span>.<span style="color:#a6e22e">shift</span>, <span style="color:#a6e22e">d</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">ellipse</span>( <span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">ishift</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">cos</span>(<span style="color:#a6e22e">dir</span>), <span style="color:#a6e22e">y</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">ishift</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">sin</span>(<span style="color:#a6e22e">dir</span>),
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">hr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">iris</span>.<span style="color:#a6e22e">size</span>, <span style="color:#a6e22e">vr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">iris</span>.<span style="color:#a6e22e">size</span> )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// pupil
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">fill</span>(<span style="color:#a6e22e">pupil</span>.<span style="color:#a6e22e">color</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">pshift</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">hr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">pupil</span>.<span style="color:#a6e22e">shift</span>, <span style="color:#a6e22e">d</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">ellipse</span>( <span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">pshift</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">cos</span>(<span style="color:#a6e22e">dir</span>), <span style="color:#a6e22e">y</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">pshift</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">sin</span>(<span style="color:#a6e22e">dir</span>),
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">hr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">pupil</span>.<span style="color:#a6e22e">size</span>, <span style="color:#a6e22e">vr</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">pupil</span>.<span style="color:#a6e22e">size</span> )
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We use <em>object deconstruction</em> syntax here
to simplify calculations, so we don&rsquo;t have
to supply each value with <code>this.</code> prefix.</p>
<p>Three ellipses are drawn here in total.
Each preceded by a <code>fill()</code> call
to set the corresponding fill color.</p>
<p>There are also some preliminary calculations
to determine the shift direction for <em>iris</em> and <em>pupil</em>.</p>
<p><strong>Collider.JAM</strong> <code>bearing()</code> and <code>dist()</code>
functions are used to calculate
the angle and distance to the mouse cursor.</p>
<h2 id="setup">setup()</h2>
<p>The setup function creates two eyes in the <code>/lab</code> node:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">setup</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// spawn two eyes
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">spawn</span>(<span style="color:#a6e22e">dna</span>.<span style="color:#a6e22e">eye</span>, {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">x</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">69</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">y</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">25</span>),
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">spawn</span>(<span style="color:#a6e22e">dna</span>.<span style="color:#a6e22e">eye</span>, {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">x</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">75</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">y</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">rx</span>(.<span style="color:#ae81ff">25</span>),
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="click">click()</h2>
<p>To create an additional eye on mouse click,
introduce a click trap in <code>trap/click.js</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// trap/click.js
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">click</span>(<span style="color:#a6e22e">e</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">spawn</span>(<span style="color:#e6db74">&#39;eye&#39;</span>, {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">x</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">x</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">y</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">mouse</span>.<span style="color:#a6e22e">y</span>,
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="green-eyes-on-the-mouse">Green Eyes on the mouse!</h2>
<p>That&rsquo;s all you need for a functioning
<a href="http://collider.land">Collider.JAM</a> app.</p>
<p>Run it from inside the <code>eyes.mod</code> folder with:</p>
<pre tabindex="0"><code>jam play
</code></pre><p>And eyes in the browser will start to track your cursor :)</p>
<p>Click anywhere on the screen to create more eyes!</p>
<p><img src="/img/2020/eyes-2.png" alt="More Eyes"></p>
<p>You can find the demo app sources on <a href="https://github.com/invadium/sketch.mix/tree/master/eyes.mod">GitHub</a>.</p>
]]></content></item><item><title>Background in Collider.JAM</title><link>https://ikhotin.com/posts/2020/12/background-in-collider.jam/</link><pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/12/background-in-collider.jam/</guid><description>&lt;p>Backgrounds are essential for any game.&lt;/p>
&lt;p>Usually, backgrounds are not a part of the action,
nevertheless, they are a crucial element of a game
style and aesthetics.&lt;/p>
&lt;p>Backgrounds also play an important role in the game loop,
since usually they are the first thing we draw each frame.
So the background is supposed to clean up the previous frame.&lt;/p>
&lt;h2 id="before-dr4">Before DR4&lt;/h2>
&lt;p>In early versions of &lt;a href="http://collider.land">Collider.JAM&lt;/a>
we used to draw backgrounds manually.&lt;/p></description><content type="html"><![CDATA[<p>Backgrounds are essential for any game.</p>
<p>Usually, backgrounds are not a part of the action,
nevertheless, they are a crucial element of a game
style and aesthetics.</p>
<p>Backgrounds also play an important role in the game loop,
since usually they are the first thing we draw each frame.
So the background is supposed to clean up the previous frame.</p>
<h2 id="before-dr4">Before DR4</h2>
<p>In early versions of <a href="http://collider.land">Collider.JAM</a>
we used to draw backgrounds manually.</p>
<p>The simplest form you can find in the early examples
would be whole screen color fill in a draw function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// lab/background.js
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">Z</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">draw</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">fill</span>(.<span style="color:#ae81ff">55</span>, .<span style="color:#ae81ff">4</span>, .<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">rect</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">ctx</span>.<span style="color:#a6e22e">width</span>, <span style="color:#a6e22e">ctx</span>.<span style="color:#a6e22e">height</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="background">background()</h2>
<p>Since backgrounds were so common, manual fill
was soon replaced by the <code>background()</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">draw</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">background</span>(.<span style="color:#ae81ff">75</span>, .<span style="color:#ae81ff">4</span>, .<span style="color:#ae81ff">1</span>) <span style="color:#75715e">// HSL values
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}
</span></span></code></pre></div><p>So you don&rsquo;t have to specify the screen size -
in the case of the background,
it is obviously the whole screen.</p>
<p>And you can use it in many different ways:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">background</span>(<span style="color:#e6db74">&#39;#252030&#39;</span>)      <span style="color:#75715e">// CSS-style color
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">background</span>(<span style="color:#ae81ff">15</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">30</span>)     <span style="color:#75715e">// RGB values
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">background</span>(<span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">background</span>) <span style="color:#75715e">// fill with a background image
</span></span></span></code></pre></div><h2 id="since-dr4">Since DR4</h2>
<p>However, backgrounds are so common, that even one function call
seems like overkill.
When you drawing a simple sketch, you need a background
just to be there. You don&rsquo;t have to care about puny details.</p>
<p>Therefore, since the <strong>Development Release 4</strong> we have
a background enabled by default.
I choose it to be dark (more precisely - a dark grey &lsquo;#121313&rsquo;).
The dark background seems to work better than a light one
for most of the examples. Also, the dark grey is better
mixed with most of the colors as opposed to the totally black &lsquo;#000000&rsquo;.</p>
<p>The default background is set as <code>background</code> property in <code>lab</code>.
If you don&rsquo;t want <code>#121313</code>, you can set it manually:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">setup</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">background</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">hsl</span>(.<span style="color:#ae81ff">75</span>, .<span style="color:#ae81ff">4</span>, .<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Or maybe set an image:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">background</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">background</span> <span style="color:#75715e">// fill with the background image
</span></span></span></code></pre></div><h2 id="complex-backgrounds">Complex Backgrounds</h2>
<p>You can turn off the background:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">lab</span>.<span style="color:#a6e22e">background</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>
</span></span></code></pre></div><p>You might want to do that to draw a complex background manually
(e.g. when you need parallax scrolling) or to preserve the scene
for the next frame in simulations like
<a href="https://github.com/invadium/bits.mix/blob/master/brownian.mod/lab.js">brownian motion</a>.</p>
<p>To make a complex background node with parallax scrolling
or other effects, just include the node in <code>/lab</code>
and make sure it has the lowest Z-value, e.g.:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// lab/background.js
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">Z</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">draw</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// some complex drawing
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}
</span></span></code></pre></div><p>Interestingly, it is just the way we used to do
backgrounds before DR4 :)</p>
<h2 id="design">Design</h2>
<p>You can see, that in Collider.JAM the default option
is the most simple and widespread one.
But any level of customization can easily be achieved
by simple overrides.</p>
<p>That little feature actually reflects an important tenet
in <a href="http://collider.land">Collider.JAM</a> design:</p>
<blockquote>
<p><em>Provide the most used case as a default option,
but give the ability to easily override with
custom behavior.</em></p></blockquote>
<p>That principle rules over many features of Collider.JAM,
not only backgrounds. You can find many reasonable defaults
all across the framework. And they are one of the key reasons
for code simplicity in Collider.JAM.</p>
]]></content></item><item><title>Collider.JAM DR9</title><link>https://ikhotin.com/posts/2020/11/collider.jam-dr9/</link><pubDate>Wed, 25 Nov 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/11/collider.jam-dr9/</guid><description>&lt;p>Yesterday, I&amp;rsquo;ve signed off and published
&lt;a href="http://collider.land">Collider.JAM Development Release 9&lt;/a>.&lt;/p>
&lt;p>The package is available on &lt;a href="https://www.npmjs.com/package/collider.jam">npm&lt;/a>:&lt;/p>
&lt;pre>&lt;code>npm install -g collider.jam
&lt;/code>&lt;/pre>
&lt;p>It&amp;rsquo;s the 8th Collider.JAM release this year.
The &lt;a href="https://github.com/invadium/collider.jam/blob/master/CHANGELOG">changelog&lt;/a>
is not as big, as in the previous release,
but still, there are significant changes.&lt;/p>
&lt;p>We finally have
&lt;a href="https://github.com/invadium/collider.jam/blob/master/CONTRIBUTING.md">CONTRIBUTING.md&lt;/a>
with tips on how one can help the project.
It&amp;rsquo;s attributed primarily to &lt;a href="https://hacktoberfest.digitalocean.com/">Hacktoberfest&lt;/a>
and the best open-source practices I&amp;rsquo;ve learned along the way.&lt;/p>
&lt;p>But this release is not about features,
it is about user experience.&lt;/p></description><content type="html"><![CDATA[<p>Yesterday, I&rsquo;ve signed off and published
<a href="http://collider.land">Collider.JAM Development Release 9</a>.</p>
<p>The package is available on <a href="https://www.npmjs.com/package/collider.jam">npm</a>:</p>
<pre><code>npm install -g collider.jam
</code></pre>
<p>It&rsquo;s the 8th Collider.JAM release this year.
The <a href="https://github.com/invadium/collider.jam/blob/master/CHANGELOG">changelog</a>
is not as big, as in the previous release,
but still, there are significant changes.</p>
<p>We finally have
<a href="https://github.com/invadium/collider.jam/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a>
with tips on how one can help the project.
It&rsquo;s attributed primarily to <a href="https://hacktoberfest.digitalocean.com/">Hacktoberfest</a>
and the best open-source practices I&rsquo;ve learned along the way.</p>
<p>But this release is not about features,
it is about user experience.</p>
<p>The readme and help are significantly improved.
The ultimate goal is to have the documentation
good enough for on-boarding without any additional help.
We still have a long road ahead to get there,
but the roadmap is in place.
And we&rsquo;ll continue to experiment with
various forms and formats to get the best results possible.</p>
<p>There is a Pong tutorial available in help now.
I feel the need for a series of tutorials
just like that - Breakout, Tetris,
Asteroids, Snake, Missile Attack&hellip;</p>
<p>Classic games are built around well-understood mechanics,
thus providing ideal tutorial material.
You don&rsquo;t have to figure out how the game works,
just discover and use the fitting blocks
of Collider.JAM and JavaScript to make it work.</p>
<p>It is a valuable lesson in pedagogy
I haven&rsquo;t defined for myself up to this point.
Although, I&rsquo;ve been using it intuitively for quite a while.</p>
<blockquote>
<p><strong>Leverage well-understood mechanics to teach new concepts.</strong></p></blockquote>
<p>Everybody knows how to play Pac-Man or fit blocks in Tetris.
We can use that as a vehicle of discovery.
E.g. explain two-dimensional arrays using the Tetris field.
The possibilities are limited only by our imagination.</p>
<p>So expect more awesome tutorials on Collider.JAM and JavaScript
in the nearest future!</p>
]]></content></item><item><title>Global Scope in Collider.JAM</title><link>https://ikhotin.com/posts/2020/11/global-scope-in-collider.jam/</link><pubDate>Tue, 17 Nov 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/11/global-scope-in-collider.jam/</guid><description>&lt;p>Global scope is considered evil.
It especially resonates in the JavaScript world
with a notorious &lt;strong>window&lt;/strong> object.
The most common advice out there is to avoid
globals as much as possible.&lt;/p>
&lt;p>However, a game state is essentially a one big &lt;em>global scope&lt;/em>.&lt;/p>
&lt;p>It defines where the enemies are,
how many hit points they have,
and how much health and ammo you&amp;rsquo;ve got.
And each part of that system potentially can affect any other.&lt;/p></description><content type="html"><![CDATA[<p>Global scope is considered evil.
It especially resonates in the JavaScript world
with a notorious <strong>window</strong> object.
The most common advice out there is to avoid
globals as much as possible.</p>
<p>However, a game state is essentially a one big <em>global scope</em>.</p>
<p>It defines where the enemies are,
how many hit points they have,
and how much health and ammo you&rsquo;ve got.
And each part of that system potentially can affect any other.</p>
<p>In reality, the global scope is not that bad if you know how to deal with it.</p>
<p><a href="http://collider.land">Collider.JAM</a> offers its own approach
of global scope organization and handling.</p>
<h2 id="the-mix">The Mix</h2>
<p>The global scope in <strong>Collider.JAM</strong> represents the scene
and all associated resources.
It is called <strong>the mix</strong> since it mixes all <strong>mods</strong> and <strong>fixes</strong>
into a single tree hierarchy.
At the top of the mix, there is <em>the root mod</em>.
All other mods are mounted inside at <code>/mod</code> by default.</p>
<p>Everything in your game is placed somewhere in the mix.
You can think of it as a virtual filesystem
that joins together all the <code>*.mod</code> and <code>*.fix</code>
folders you have plus all the system <code>*mod</code> and <code>*.fix</code>
folders shipped with <em>Collider.JAM</em>.</p>
<p>The mixing process is pretty straightforward - you start
with a bunch of <em>mod &amp; fix</em> folders and load them
into a single tree at particular mount points.</p>
<h2 id="-global-accessor">$ Global Accessor</h2>
<p>By default, the whole <strong>mix</strong> hierarchy is exported as a <strong>$</strong> object.</p>
<p>It is done primarily for the convenience of debugging.
You can always open the browser developer console
and type <code>$</code> to dump the whole mix,
or maybe <code>$.lab.hero</code> to dump the hero object.</p>
<p>Since Collider.JAM DR9, the <code>$</code> object is defined
both as a global variable and as a variable within Collider.JAM scope.</p>
<p>The reason is that the global <strong>$</strong> can be disabled
to restrict the access to mix from the outside:</p>
<pre tabindex="0"><code>delete window.$
</code></pre><p>or</p>
<pre tabindex="0"><code>window.$ = null
</code></pre><p>Also, it can be reused for other purposes.</p>
<p>But within Collider.JAM scope, the <code>$</code>
will still be pointing at the mix.</p>
<p>Almost everything in your game can be accessed through <code>$.*</code>
since everything is placed as a node on the mix tree. It is truly the global context of the game. The rare exception would be the data and functions hidden inside closures.</p>
<h2 id="local-mod">Local Mod</h2>
<p>In most cases, you don&rsquo;t need to access <em>the root mod</em>.</p>
<p>Usually, you work with the current <em>mod</em>
and there are a bunch of links in scope to access it.
We call it <strong>a local mod context</strong>, but it is not truly local.
Better think of it as a global context of the current mod.</p>
<p>There is the <code>_</code> accessor that points to the current mod.</p>
<p>There are also fast node accessors like <code>res</code>, <code>env</code>, <code>dna</code>,
<code>lab</code> and <code>trap</code>. You can use them for quick access
to particular components of the current mod.</p>
<p>Let&rsquo;s assume you need to run the <code>show()</code> function
on <code>hud</code> object in <code>console.mod</code>.</p>
<p>You can access it from anywhere by using the mix <code>$</code> accessor:</p>
<pre tabindex="0"><code>$.mod.console.lab.hud.show()
</code></pre><p>But within <code>console.mod</code> you can say:</p>
<pre tabindex="0"><code>_.lab.hud.show()
</code></pre><p>Or even better, use the <code>lab</code> shortcut:</p>
<pre tabindex="0"><code>lab.hud.show()
</code></pre><p>By using the local path instead of global, you make code shorter and more portable.
You can rename the mod or mount it at another node of the tree
and all the local links will continue to work without any changes.</p>
<h2 id="_-and-">_ and $</h2>
<p>Accessors <code>_</code> and <code>$</code> are the main things you need to know
about the global scope in Collider.JAM.</p>
<p>Use <code>_</code> to access current <em>mod</em>.</p>
<p>Use <code>$</code> when you need to access things globally in other <em>mods</em>.</p>
<p>Also, use <code>$</code> in the browser dev console.
The <code>_</code> accessor is defined only within each <em>mod&rsquo;s</em> scope
and makes no sense in the browser dev console context.</p>
<h2 id="colliderjam-global-context">Collider.JAM Global Context</h2>
<p>It would be unfair if I&rsquo;ll not mention other objects
in Collider.JAM global context.</p>
<p>Besides the <code>_</code> and <code>$</code>, there are many more
things defined in the <em>mod</em> scope.</p>
<p>There are drawing functions like <code>line()</code>, <code>rect()</code>, and <code>circle()</code>.</p>
<p>There are math functions like <code>sin()</code>, <code>cos()</code>, and <code>sqrt()</code>.</p>
<p>There are utility functions like <code>defer()</code> and <code>kill()</code>.</p>
<p>But these would require more than a single post  to cover them properly,
so see you the next time.</p>
]]></content></item><item><title>Collider.JAM Debug Mode</title><link>https://ikhotin.com/posts/2020/11/collider.jam-debug-mode/</link><pubDate>Thu, 12 Nov 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/11/collider.jam-debug-mode/</guid><description>&lt;p>It is easy to run a &lt;a href="http://collider.land">Collider.JAM&lt;/a> project.&lt;/p>
&lt;p>Just execute somewhere inside a project folder:&lt;/p>
&lt;pre tabindex="0">&lt;code>jam
&lt;/code>&lt;/pre>&lt;p>And then open &lt;a href="http://localhost:9999">http://localhost:9999&lt;/a>.&lt;/p>
&lt;p>Even better, you can ask Collider.JAM to open the project link automatically:&lt;/p>
&lt;pre tabindex="0">&lt;code>jam play
&lt;/code>&lt;/pre>&lt;p>However, during development we often use a different form:&lt;/p>
&lt;pre tabindex="0">&lt;code>jam -d
&lt;/code>&lt;/pre>&lt;p>The &lt;code>-d&lt;/code> flag turns on the &lt;strong>debug mode&lt;/strong>.
There are a number of debug and development features enabled by this:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="#debug-output-in-the-terminal">debug output&lt;/a>&lt;/li>
&lt;li>&lt;a href="#fast-boot">fast boot&lt;/a>&lt;/li>
&lt;li>&lt;a href="#help-data">help data&lt;/a>&lt;/li>
&lt;li>&lt;a href="#hot-reload">hot reload&lt;/a>&lt;/li>
&lt;li>&lt;a href="#custom-debug-hooks">custom debug hooks&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="debug-output-in-the-terminal">Debug output in the terminal&lt;/h2>
&lt;p>The debug output prints a lot of data
besides the usual Collider.JAM version and listening address.&lt;/p></description><content type="html"><![CDATA[<p>It is easy to run a <a href="http://collider.land">Collider.JAM</a> project.</p>
<p>Just execute somewhere inside a project folder:</p>
<pre tabindex="0"><code>jam
</code></pre><p>And then open <a href="http://localhost:9999">http://localhost:9999</a>.</p>
<p>Even better, you can ask Collider.JAM to open the project link automatically:</p>
<pre tabindex="0"><code>jam play
</code></pre><p>However, during development we often use a different form:</p>
<pre tabindex="0"><code>jam -d
</code></pre><p>The <code>-d</code> flag turns on the <strong>debug mode</strong>.
There are a number of debug and development features enabled by this:</p>
<ul>
<li><a href="#debug-output-in-the-terminal">debug output</a></li>
<li><a href="#fast-boot">fast boot</a></li>
<li><a href="#help-data">help data</a></li>
<li><a href="#hot-reload">hot reload</a></li>
<li><a href="#custom-debug-hooks">custom debug hooks</a></li>
</ul>
<hr>
<h2 id="debug-output-in-the-terminal">Debug output in the terminal</h2>
<p>The debug output prints a lot of data
besides the usual Collider.JAM version and listening address.</p>
<p>It shows the type of project it runs
(sketch mod, sketch mix or package),
what configurations are found and used,
the scan map used to find and inspect all the units.</p>
<p>It prints all the files and folders it has found,
which ones are included and which ones are ignored.</p>
<p>It shows where exactly the found units are mounted
on the webserver.</p>
<p>If you are missing a resource, it is the first place to look.
Maybe Collider.JAM scans wrong folders or the file is ignored
for some reason.</p>
<h2 id="fast-boot">Fast Boot</h2>
<p>Collider.JAM tries to minimize the load time when in
<em>debug mode</em>.
Keeping <strong>[Change-&gt; Reload -&gt; Try ↵]</strong> cycle short
is crucial for a jamming-style development.</p>
<h2 id="help-data">Help Data</h2>
<p>Collider.JAM collects help data only in <em>debug mode</em>.</p>
<p>Open the project and use <strong>F1</strong> to access the help system.
It includes a lot of useful information - how to get started
with Collider.JAM, useful links, tutorials, documentation
on framework libraries, and your own objects and prototypes.</p>
<h2 id="hot-reload">Hot Reload</h2>
<p>This feature significantly speeds up the tuning process.</p>
<p>Collider.JAM scans the included folders for changes
and reloads all changed files.</p>
<p>Hot reload works well for things like
<strong>/dna</strong>, <strong>/env</strong>, <strong>/lib</strong> and static resources,
but can be tricky for entities in <strong>/lab</strong>.</p>
<p>The ones placed directly in <strong>/lab</strong> are mostly OK.
The entities spawned from DNA, on the other hand,
have an evolved state associated with them that can&rsquo;t be changed.
Collider.JAM tries to patch the functions in order to upgrade behavior.
But there is a change it can brake the entity -
especially if a new state has been introduced in updated DNA.</p>
<p>Therefore, sometimes full page reload is necessary
to get a consistent update.
But if you are changing resources or tuning colors
in <em>/env/tune.js</em>, it works just fine.</p>
<h2 id="custom-debug-hooks">Custom Debug Hooks</h2>
<p>The last significant feature of <em>debug mode</em> is
custom hooks you can add for development and debugging.</p>
<p>When you run the projects with <code>jam -d</code>,
the environment configuration has <code>debug</code> flag activated.
So you can introduce debug-only code in your project
as simple as:</p>
<pre tabindex="0"><code>if (env.config.debug) {
    // TODO enable debug feature or log debug info
}
</code></pre><hr>
<h2 id="useful-by-default">Useful by default</h2>
<p>I always run <em>Collider.JAM</em> with the <code>-d</code> flag
while working on a project.
The debug features are really useful and have no practical downsides.</p>
<p>Only when I want to see the release version, I skip the <code>-d</code>.</p>
]]></content></item><item><title>Sketch Projects in Collider.JAM</title><link>https://ikhotin.com/posts/2020/11/sketch-projects-in-collider.jam/</link><pubDate>Tue, 10 Nov 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/11/sketch-projects-in-collider.jam/</guid><description>&lt;p>The development tools today are big. And that directly reflects
on the complexity of projects they produce.&lt;/p>
&lt;p>The level of noise modern tools generate is just unbelievable.
When you click on &amp;ldquo;Create a New Project&amp;rdquo;
in a typical modern IDE, you receive a folder
full of mystery and surprises.&lt;/p>
&lt;p>A hello-world type of project might consist of hundreds of files.&lt;/p>
&lt;p>Do these files essential?
Do they serve any purpose?
Is it possible to hide or eliminate some of them
while preserving the functionality?
Is it really necessary to be that complex?&lt;/p></description><content type="html"><![CDATA[<p>The development tools today are big. And that directly reflects
on the complexity of projects they produce.</p>
<p>The level of noise modern tools generate is just unbelievable.
When you click on &ldquo;Create a New Project&rdquo;
in a typical modern IDE, you receive a folder
full of mystery and surprises.</p>
<p>A hello-world type of project might consist of hundreds of files.</p>
<p>Do these files essential?
Do they serve any purpose?
Is it possible to hide or eliminate some of them
while preserving the functionality?
Is it really necessary to be that complex?</p>
<p>I believe <a href="http://collider.land">Collider.JAM</a> has an answer to this problem.
We put all the effort to make projects smooth and clean.
You put in only the essentials.
And it is a good example of minimalistic design.</p>
<h2 id="sketch-mod">sketch mod</h2>
<p>In <em>Collider.JAM</em> you don&rsquo;t need an IDE to create a project.
You just type:</p>
<pre tabindex="0"><code>mkdir test.mod
</code></pre><p>That&rsquo;s it! Simply create a folder named <code>*.mod</code>,
cd into it, and you can already run it with:</p>
<pre tabindex="0"><code>jam play
</code></pre><p>It doesn&rsquo;t show anything, but it works!</p>
<p>It represents a <em>mod</em> - the most fundamental concept
in <em>Collider.JAM</em>, that defines both structure and behavior.
And you can already explore that structure by hitting F2.</p>
<p>To have something on the screen, you might create <code>lab.js</code> inside:</p>
<pre tabindex="0"><code>function draw() {
    fill(.35, .5, .5)
    cirlce(rx(.5), ry(.5), 50)
}
</code></pre><p>Now you filled a circle in the center.</p>
<p>This type of <em>Collider.JAM</em> project is called <em>sketch mod</em>.
We don&rsquo;t have to create <code>package.json</code> or any other boilerplate files
for it to work.</p>
<p>Just a simple folder with content sorted in subfolders.
The extension <code>*.mod</code> is important though.
It is how <em>Collider.JAM</em> recognizes the root of the project.</p>
<p>The structure inside <code>*.mod</code> have to follow
<em>Collider.JAM</em> conventions.
It means factories and prototypes go to <em>/dna</em>,
utility functions are placed in <em>/lib</em>,
event handlers are in <em>/trap</em>,
and everything that lives is in <em>/lab</em>.</p>
<p>These folders represent conventions used by <em>Collider.JAM</em>
to locate and use different game components.
It is similar to conventions used by some web frameworks
like <em>Ruby on Rails</em> to locate models, views, and controllers.
Placing a <code>*.js</code> file in different folders can change its behavior.</p>
<p>The <em>mod</em> structure might look daunting at first.
But it turns into a familiar landscape once you used it
for a little while.
And when you know it, it becomes easy to navigate <em>Collider.JAM</em> projects, especially the more complex <em>mixes</em> consisting
of multiple <em>modes</em>.</p>
<p>The best thing is that you don&rsquo;t need to know the whole
<strong>mod</strong> structure to start the development.
Just <a href="/posts/2020/10/4-essential-folders-in-collider.jam/">4 essential folders</a> will suffice.</p>
<h2 id="jam-new">jam new</h2>
<p>Sometimes we don&rsquo;t want to create a structure manually.</p>
<p><em>Collider.JAM</em> provides some helpers to do it automatically.
Run <code>new ls</code> command to see the possible options:</p>
<pre tabindex="0"><code>jam new ls
</code></pre><p>Let&rsquo;s create a sample mod:</p>
<pre tabindex="0"><code>jam new mod sample
</code></pre><p>This generates a <code>sample.mod</code> folder with a typical structure -
there are <em>dna</em>, <em>lab</em>, <em>lib</em>, <em>res</em>, and <em>trap</em> examples generated.
Run the <em>mod</em> to see the result:</p>
<pre tabindex="0"><code>cd sample.mod
jam play
</code></pre><h2 id="sketch-mixes-and-packages">sketch mixes and packages</h2>
<p>There are other types of projects in <em>Collider.JAM</em> - sketch mixes and packages.
They are usually used in more special cases.</p>
<p>For example, when packaging the game for a mobile platform or desktop,
you need to have a <code>package.json</code> with appropriate dependencies.
So these projects are created in the so-called &ldquo;package mode&rdquo;.</p>
<p>But in most cases, you can start in <em>the sketch mode</em>
and move to <em>the package mode</em> later.</p>
<p>The world is a very noisy place. You don&rsquo;t need more noise in your <em>Collider.JAM</em> projects. So stick with the sketch mode whenever possible.</p>
]]></content></item><item><title>Ton Roosendall and the Story of Blender</title><link>https://ikhotin.com/posts/2020/10/ton-roosendall-and-the-story-of-blender/</link><pubDate>Sat, 31 Oct 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/10/ton-roosendall-and-the-story-of-blender/</guid><description>&lt;p>The best way to close &lt;strong>Hacktoberfest 2020&lt;/strong> is to share a story.
And what can be better, than a fascinating story of pixels, polygons, and open source?&lt;/p>
&lt;p>In &lt;a href="https://youtu.be/qJEWOTZnFeg">this video&lt;/a>,
Blender Guru talks with Ton Roosendaal about the origins and the future of Blender.&lt;/p>
&lt;p>Blender originated in 3D animation studio NeoGeo
on the Amiga platform in the late 80s.
You can still &lt;a href="https://download.blender.org/source/chest/neogeo/Amiga-software.zip">download and try&lt;/a>
the original software called Traces.&lt;/p>
&lt;p>Later, a company Not A Number was formed to support the development of 3D modeler by that time called Blender.&lt;/p></description><content type="html"><![CDATA[<p>The best way to close <strong>Hacktoberfest 2020</strong> is to share a story.
And what can be better, than a fascinating story of pixels, polygons, and open source?</p>
<p>In <a href="https://youtu.be/qJEWOTZnFeg">this video</a>,
Blender Guru talks with Ton Roosendaal about the origins and the future of Blender.</p>
<p>Blender originated in 3D animation studio NeoGeo
on the Amiga platform in the late 80s.
You can still <a href="https://download.blender.org/source/chest/neogeo/Amiga-software.zip">download and try</a>
the original software called Traces.</p>
<p>Later, a company Not A Number was formed to support the development of 3D modeler by that time called Blender.</p>
<p>Initially, Blender was a freemium software.
You can download a basic version for free
and get the full-featured one for money.</p>
<p>But the company has failed to generate enough sales
and investors decided to close the operations.</p>
<p>So Ton Roosendaal came up with a truly unique solution -
announce a crowd-sourcing campaign to gather 100,000 EUR
for NaN investors to free Blender under an open-source license.
The campaign was highly successful and reached the goal
in just 7 weeks.</p>
<p>It is probably one of the first crowd-sourcing campaigns on record and it is highly remarkable for turning a commercial software product into an open-source one.</p>
<p>When I was working in game development in the late 2000s,
Blender wasn&rsquo;t considered to be a true &ldquo;professional&rdquo; option.
Except for a rare few enthusiasts, most artists sticked to MAX and Maya.</p>
<p>But today, with each new release, Blender gains momentum over the competition. It shows the actual power of the open-source community and the huge challenges commercial software vendors face.</p>
<p>In some areas, open-source already had a decisive victory.</p>
<p>In the 80s and the 90s, most developers were buying their compilers, linkers, profilers, and other tools. Nobody thinks about buying a compiler today. It is inconceivable now since we used to get our SDKs for free (except for some special cases - do you hear me, game console vendors?).</p>
<p>So I love this time when our platforms and tools are open-sourced. The technologies today are more accessible than ever before.</p>
<p>The future is already here! And the future is open-source!</p>
]]></content></item><item><title>The Essence of Life in Collider.JAM</title><link>https://ikhotin.com/posts/2020/10/the-essence-of-life-in-collider.jam/</link><pubDate>Fri, 30 Oct 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/10/the-essence-of-life-in-collider.jam/</guid><description>&lt;p>Lifeforms of &lt;a href="http://collider.land">Collider.JAM&lt;/a>
live in the &lt;em>/lab&lt;/em>, as you might know from
my previous &lt;a href="https://ikhotin.com/posts/2020/10/4-essential-folders-in-collider.jam/">post&lt;/a>.&lt;/p>
&lt;p>&lt;strong>The Essence of Life&lt;/strong> is simple
and ruled only by 2 functions - &lt;code>evo(dt)&lt;/code> and &lt;code>draw()&lt;/code>.
The first determines the lifeform&amp;rsquo;s behavior in a short timespan
(usually a single frame).
The second - how the lifeform looks in its current state.&lt;/p>
&lt;p>To have a lifeform on the screen,
you just have to define these two functions
on any object and place it in &lt;em>/lab&lt;/em>.&lt;/p></description><content type="html"><![CDATA[<p>Lifeforms of <a href="http://collider.land">Collider.JAM</a>
live in the <em>/lab</em>, as you might know from
my previous <a href="/posts/2020/10/4-essential-folders-in-collider.jam/">post</a>.</p>
<p><strong>The Essence of Life</strong> is simple
and ruled only by 2 functions - <code>evo(dt)</code> and <code>draw()</code>.
The first determines the lifeform&rsquo;s behavior in a short timespan
(usually a single frame).
The second - how the lifeform looks in its current state.</p>
<p>To have a lifeform on the screen,
you just have to define these two functions
on any object and place it in <em>/lab</em>.</p>
<blockquote>
<p>Note, that you don&rsquo;t have to extend from any special class
like GameObject or do any other crazy stuff.</p>
<p>You and only you define how your objects are going
to be created and organized.
Collider.JAM just provides some conventions to simplify that.</p>
<p>You can use a prototype hierarchy,
you can use a composition of mixins,
you can create custom factories&hellip;</p></blockquote>
<h2 id="moving-circle">Moving Circle</h2>
<p>Let&rsquo;s create a circle that moves horizontally:</p>
<pre tabindex="0"><code>// === mover.mod/lab.js ===

// coordinates and radius
let   x = rx(.5)  // center horizontally
const y = ry(.5)  // center vertically
const r = ry(.05) // 5% of the screen height

const SPEED = rx(.25) // 25% of the screen width per second

function evo(dt) {
    // move the circle horizontally
    // warp the coordinate, so it always stays on the screen
    x = warp(x + SPEED*dt, 0, rx(1))
}

function draw() {
    fill(.45, .5, .5) // color in HSL
    circle(x, y, r)
}
</code></pre><p>We are placing our entity directly in <code>/lab.js</code>.
It is OK as long as we are not going to have any other lifeforms. Otherwise, it is better to place it deeper, e.g. <code>/lab/circle.js</code>.</p>
<blockquote>
<p>You can run it by typing <code>jam</code> in the <code>mover.mod</code> folder.
Check the sources at <a href="https://github.com/invadium/bits.mix/tree/master/mover.mod">GitHub</a>.</p></blockquote>
<p>After initializing coordinates, radius and speed,
we are defining functions <code>evo(dt)</code> and <code>draw()</code>.</p>
<p>The purpose of <code>evo(dt)</code> is to update object state before the next drawing cycle.
In our case, it determines the movement behavior of the circle.
Each step, it moves to the right at the declared <em>SPEED</em> in pixels/second.</p>
<blockquote>
<p>Note, it is crucial to factor on <strong>dt</strong>
everything you do in <code>evo(dt)</code>.
It represents the time in seconds passed after the last update.</p>
<p>Since the speed is defined in pixels per second,
we need to factor the speed value like <code>SPEED * dt</code>
to find the actual movement over the X-axis
for the current frame.</p>
<p>When properly factored, the movement
doesn&rsquo;t depend on the actual framerate.</p></blockquote>
<p>The <code>draw()</code> function sets the fill color and draws the circle.</p>
<p>Each frame, all lifeforms in <em>/lab</em> evolve with their <code>evo(dt)</code> and rendered on the screen with their <code>draw()</code> functions.</p>
<p>Any object within the <em>/lab</em> subtree with <code>evo(dt)</code> and <code>draw()</code> functions is an actor on the scene. It shows something and behaves somehow.</p>
<h2 id="plants">Plants</h2>
<p>Some lifeforms might have only a <code>draw()</code> function. So they are not <em>actors</em> on the scene, but <em>props</em>. We call them <em>plants</em> since they have a visual representation, but no behavior of their own.</p>
<p>It might be an ammo indicator, showing the hero&rsquo;s ammo supply.
Or maybe a score indicator. Or a static wall&hellip;</p>
<h2 id="ghosts">Ghosts</h2>
<p>Plants are visible but static.
But what if we have behavior, but no visual representation whatsoever.
These entities are called <strong>ghosts</strong> and they have <code>evo(dt)</code>
but no <code>draw()</code> function defined</p>
<p>A collision detection node can be an example of <strong>a ghost</strong>.</p>
<h2 id="summary">Summary</h2>
<p>That is all there is to life in Collider.JAM. Only two functions are needed to define how lifeforms look and behave.</p>
<p>But <code>evo(dt)</code> and <code>draw()</code> are not the only <em>convention functions</em> you can define on nodes in Collider.JAM.
There are also <code>init()</code>, <code>onSpawn()</code>, <code>kill()</code>&hellip;</p>
<p>But I&rsquo;ll save them for another time :)</p>
]]></content></item><item><title>4 Essential Folders in Collider.JAM</title><link>https://ikhotin.com/posts/2020/10/4-essential-folders-in-collider.jam/</link><pubDate>Tue, 27 Oct 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/10/4-essential-folders-in-collider.jam/</guid><description>&lt;p>There are 4 essential elements in alchemy - earth, water, air, and fire. You need to understand them all to do the magic.&lt;/p>
&lt;p>&lt;a href="http://collider.land">Collider.JAM&lt;/a> framework has its own majik. To master it, you need to know 4 essential folders.&lt;/p>
&lt;p>These folders are:&lt;/p>
&lt;ul>
&lt;li>/res&lt;/li>
&lt;li>/dna&lt;/li>
&lt;li>/lab&lt;/li>
&lt;li>/trap&lt;/li>
&lt;/ul>
&lt;p>You can find them at the root of almost any Collider.JAM project.
Place files into proper folders to leverage the power of Collider.JAM.&lt;/p>
&lt;blockquote>
&lt;p>The names may look cryptic at first.
You have to get used to it.&lt;/p></description><content type="html"><![CDATA[<p>There are 4 essential elements in alchemy - earth, water, air, and fire. You need to understand them all to do the magic.</p>
<p><a href="http://collider.land">Collider.JAM</a> framework has its own majik. To master it, you need to know 4 essential folders.</p>
<p>These folders are:</p>
<ul>
<li>/res</li>
<li>/dna</li>
<li>/lab</li>
<li>/trap</li>
</ul>
<p>You can find them at the root of almost any Collider.JAM project.
Place files into proper folders to leverage the power of Collider.JAM.</p>
<blockquote>
<p>The names may look cryptic at first.
You have to get used to it.</p>
<p>After using Collider.JAM for a while,
you might appreciate the design decision to use
short lowercase names for widely used concepts.</p>
<p>This is one of the cases, where UNIX philosophy
had a major impact on Collider.JAM design.</p></blockquote>
<h2 id="res">/res</h2>
<p>All assets go here.</p>
<p>In <code>/res</code> you can find a bunch of  *.png, *.svg, *.ttf, *.wav, *.txt, *.csv and *.json files among other things. These are the resources used by the game code.</p>
<p>Since most of games contain many similar resources, they can be grouped in subfolders, e.g.:</p>
<pre tabindex="0"><code>/res/tiles - for tilesets
/res/fnt - for fonts
/res/sfx - for sound effects
/res/backgrounds - for various background images
</code></pre><p>Resources, like everything else, are loaded automatically. So there is no need to <code>load()</code> them explicitly.</p>
<p>Do you need to draw a Moon sprite? Just place <code>moon.png</code> in <code>/res</code>. Now you can render it in any draw() function:</p>
<pre tabindex="0"><code>function draw() {
    image(res.moon, 100, 100, 75, 75)
}
</code></pre><h2 id="dna">/dna</h2>
<p>It is the place for factories and prototypes.</p>
<p>Say, your main hero is implemented as <code>class Hero</code>. Place the source into <code>/dna/Hero.js</code>. Now you can spawn the hero in <code>lab</code> during the game setup:</p>
<pre tabindex="0"><code>// setup.js

function setup() {
    lab.spawn(&#39;Hero&#39;, {
        name: &#39;hero&#39;,
        health: 100,
        x: 100,
        y: 100,
    })
}
</code></pre><p>The logic is simple - you need DNA to create a lifeform.
And DNA determines the lifeform view and behavior - with functions  <code>draw()</code> and <code>evo(dt)</code>.</p>
<h2 id="lab">/lab</h2>
<p>All lifeforms are spawned in <code>/lab</code>.</p>
<p>When you need something in the game to be visible and moving, you place it in <code>/lab</code>.</p>
<p>Sometimes, we spawn lifeforms from <code>/dna</code>.
And sometimes we just place them directly in <code>/lab</code> like this:</p>
<pre tabindex="0"><code>// lab/redCircle.js

function draw() {
    fill(.01, .5, .5) // color in HSL
    circle( rx(.5), ry(.5), 75 )
}
</code></pre><p>This will create a node named &ldquo;redCircle&rdquo; that renders&hellip; a red circle in the middle of the screen.</p>
<blockquote>
<p>Note, that the color is in HSL.
But it can also be represented as RGB values like <code>fill(255, 0, 0)</code>
or even as a css-styled string like <code>fill('#ff0000')</code>.</p>
<p>Functions rx() and ry() can be read as &ldquo;screen-relative&rdquo; x and y.</p></blockquote>
<h2 id="trap">/trap</h2>
<p>All events are &ldquo;trapped&rdquo; in <code>/trap</code>.</p>
<p>These can be system events - mouse clicks, keypresses, etc&hellip;
Or they can be user-defined events like &ldquo;gameOver&rdquo; or &ldquo;levelComplete&rdquo;.</p>
<p>Traps are just functions placed in <code>/trap</code>.</p>
<p>To trap the <strong>Space key down</strong> event, define:</p>
<pre tabindex="0"><code>// trap/spaceDown.js
function spaceDown() {
    // TODO handle space key down
}
</code></pre><p>User-defined events can be trapped by the <code>trap()</code> function:</p>
<pre tabindex="0"><code>trap(&#39;gameOver&#39;)
trap(&#39;startLevel&#39;, 1)
</code></pre><p>To handle the <strong>startLevel</strong> event, create <code>startLevel()</code> function in <code>startLevel.js</code> like so:</p>
<pre tabindex="0"><code>// trap/startLevel.js
function startLevel(nextLevel) {
    // TODO start the level specified in the nextLevel parameter
}
</code></pre><h2 id="4-the-game">4 the Game</h2>
<p>These 4 folders represent all essential elements of any game.
Sprites, tiles, sound effects, and music are stored in <strong>/res</strong>.
Entities you can spawn are placed in <strong>/dna</strong>.
<strong>/lab</strong> keeps everything that lives.
And <strong>/trap</strong> traps all controls.</p>
<p>Given a simple arcade game, you hardly gonna need anything else.</p>
<h2 id="other-folders">Other Folders</h2>
<p>There are other top-level folders in Collider.JAM. Some more important than others. Like <strong>/env</strong> that is used to store configuration and global environment (e.g. things like game score). Or <strong>/lib</strong> that&rsquo;s dedicated to utility functions. Or <strong>/cue</strong> with timed triggers&hellip;</p>
<p>But the 4 highlighted folders are the most used ones. So it is crucial to know and understand them. This is the way Collider.JAM game development works.</p>
]]></content></item><item><title>Hacktoberfest 2020</title><link>https://ikhotin.com/posts/2020/10/hacktoberfest-2020/</link><pubDate>Wed, 14 Oct 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/10/hacktoberfest-2020/</guid><description>&lt;p>I&amp;rsquo;m joining Hacktoberfest 2020.&lt;/p>
&lt;p>What is the best thing after delivering Collider.JAM DR8? Sure thing it is Collider.JAM DR9. And that is what I plan to ship in late October - early November.&lt;/p>
&lt;p>The last release was dedicated to our team&amp;rsquo;s participation in
&lt;a href="https://ldjam.com/events/ludum-dare/47">Ludum Dare 47 Jam&lt;/a>. So it included mostly the features needed in jams - features for rapid development, like &lt;code>jam new&lt;/code> command that simplifies the creation of various entities.&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;m joining Hacktoberfest 2020.</p>
<p>What is the best thing after delivering Collider.JAM DR8? Sure thing it is Collider.JAM DR9. And that is what I plan to ship in late October - early November.</p>
<p>The last release was dedicated to our team&rsquo;s participation in
<a href="https://ldjam.com/events/ludum-dare/47">Ludum Dare 47 Jam</a>. So it included mostly the features needed in jams - features for rapid development, like <code>jam new</code> command that simplifies the creation of various entities.</p>
<p>But Hacktoberfest is all about open-source community, so the next release will be all about people, not technology.</p>
<p>I firmly believe that <a href="https://github.com/invadium/collider.jam">Collider.JAM</a>
offers a very unique and unobstructive way to develop interactive applications. It gives a totally different perspective on development - the one you will not find in regular IDE-oriented game engines and frameworks.</p>
<p>Some people are quite happy to work in heavy-duty environments with hundreds of panels, buttons, and checkboxes. And that is totally fine.</p>
<p>I myself prefer a more straightforward and text-oriented way when code and mechanics are not hidden behind incomprehensive UI but sorted neatly in folders around me as plain .js files. And the same code and structure are there when I load the project in a web browser. That gives me the feeling of control and understanding of what is going on inside my game.</p>
<p>I&rsquo;m sure there are people out there who are like me. Who is not satisfied by the &ldquo;black box&rdquo; approach and prefer to understand what is going on under the hood. These people are the ones I&rsquo;m gonna try to reach. These are the people who can get and appreciate the vision of Collider.</p>
<p>And reaching those people are going to be my Hacktoberfest.</p>
]]></content></item><item><title>Collider.JAM DR8</title><link>https://ikhotin.com/posts/2020/10/collider.jam-dr8/</link><pubDate>Thu, 08 Oct 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/10/collider.jam-dr8/</guid><description>&lt;p>&lt;a href="http://colliderlabs.com/jam/">Collider.JAM&lt;/a> Development Release 8 is out.&lt;/p>
&lt;p>It is the first release for which I can claim more or less full help coverage. Finally, the big and complex prototypes in &lt;em>/hud&lt;/em> are fully documented. And it feels good. Now I can focus on missing tutorials.&lt;/p>
&lt;p>There are a lot of changes delivering more consistency and convenience.&lt;/p>
&lt;p>Like Frame&amp;rsquo;s &lt;em>select()&lt;/em> and &lt;em>selectOne()&lt;/em> methods now support asterix patterns and JQuery/CSS-like selectors. So you can get all instances of Missile proto in &lt;em>/lab&lt;/em> like &lt;code>lab.select('.Missile')&lt;/code> or maybe select them by id like &lt;code>lab.select('#missile*')&lt;/code> or name like &lt;code>lab.select('&amp;amp;missile*')&lt;/code>. Consistent.&lt;/p></description><content type="html"><![CDATA[<p><a href="http://colliderlabs.com/jam/">Collider.JAM</a> Development Release 8 is out.</p>
<p>It is the first release for which I can claim more or less full help coverage. Finally, the big and complex prototypes in <em>/hud</em> are fully documented. And it feels good. Now I can focus on missing tutorials.</p>
<p>There are a lot of changes delivering more consistency and convenience.</p>
<p>Like Frame&rsquo;s <em>select()</em> and <em>selectOne()</em> methods now support asterix patterns and JQuery/CSS-like selectors. So you can get all instances of Missile proto in <em>/lab</em> like <code>lab.select('.Missile')</code> or maybe select them by id like <code>lab.select('#missile*')</code> or name like <code>lab.select('&amp;missile*')</code>. Consistent.</p>
<p>Also, select() and selectOne() are global functions now looking at the <em>/lab</em> node (convenient).</p>
<p>There are many other cool features. Like require() to require dependent nodes, defer() to schedule function call after the game loop iteration, on&hellip;() events support in <em>/lab</em>, and new debug console commands for the mix navigation.</p>
<p>And finally, the promised change for package mixes. Even when run globally, <em>Collider.JAM</em> uses local packages by default now, unless the <em>&ndash;global</em> flag is specified.</p>
<p>So, try the new release by installing it directly from the npm registry:</p>
<pre tabindex="0"><code>npm install -g collider.jam
</code></pre><p>Enjoy!</p>
]]></content></item><item><title>The Road to Collider.JAM DR8</title><link>https://ikhotin.com/posts/2020/09/the-road-to-collider.jam-dr8/</link><pubDate>Fri, 25 Sep 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/09/the-road-to-collider.jam-dr8/</guid><description>&lt;p>I&amp;rsquo;ve shipped 6 releases of &lt;a href="http://colliderlabs.com/jam/">Collider.JAM&lt;/a> this year so far. It&amp;rsquo;s a great improvement from a single release in 2019 :)&lt;/p>
&lt;p>The framework is getting more usable out of the box. DR7 has brought an immense improvement in help quality. But we are still missing introductory materials. Simple tutorials in help and readme are all we have. Also, there is a bunch of demo mods in &lt;a href="https://github.com/invadium/bits.mix">bits.mix&lt;/a> that might be useful for starters. But that is about it.&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;ve shipped 6 releases of <a href="http://colliderlabs.com/jam/">Collider.JAM</a> this year so far. It&rsquo;s a great improvement from a single release in 2019 :)</p>
<p>The framework is getting more usable out of the box. DR7 has brought an immense improvement in help quality. But we are still missing introductory materials. Simple tutorials in help and readme are all we have. Also, there is a bunch of demo mods in <a href="https://github.com/invadium/bits.mix">bits.mix</a> that might be useful for starters. But that is about it.</p>
<p>To remedy this, I&rsquo;m shooting a bunch of video tutorials to publish on <a href="https://www.youtube.com/channel/UCbdjnUl8SlqsjhdcNMnKSPQ">Invadium</a>(EN) and <a href="https://www.youtube.com/channel/UCrfgjpkw0NN8JclL1HNmlOQ">PowerUps</a>(RU) channels. And also preparing a set of tutorials to publish on this blog first and some other platforms later.</p>
<p>I&rsquo;ve established that tradition to ship Collider.JAM releases for game jams. I&rsquo;ve shipped a new version for 7DRL Challenge, Ludum Dare 46, HyperCasual Jam, and GameBoy Jam.</p>
<p>Collider.JAM Development Release 8 is not going to be an exception and I plan to deliver it before the upcoming Ludum Dare 47.</p>
<p>Don&rsquo;t expect big features. Many minor bug fixes and help system improvements are going to be included. Plus already mentioned tutorials.</p>
<p>As soon as we have a stable core covered with tests, help, and tutorials, we will deliver the last Development Release (9? 10? 11? It&rsquo;s not clear yet) and start a new era for that unique and amazing framework.</p>
]]></content></item><item><title>How to Prepare for Your Next Game Jam</title><link>https://ikhotin.com/posts/2020/07/how-to-prepare-for-your-next-game-jam/</link><pubDate>Mon, 27 Jul 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/07/how-to-prepare-for-your-next-game-jam/</guid><description>&lt;p>Participation in another game jam brings some thoughts on how to prepare properly.&lt;/p>
&lt;p>Since I had my share of defeats as well as successful jams, I want to share my experience and lay down some things you can do to make the upcoming jam as smooth and productive, as possible.&lt;/p>
&lt;p>&lt;img src="https://ikhotin.com/img/2020/negative-laptop-notepad.jpeg" alt="Laptop and Notepad">&lt;/p>
&lt;p>Jams, Sprints, and Hackathons are hyper-intensive events and you want to be ready beforehand.
Skipping preparations and just diving in can result in wasting valuable time, losing the flow, and even failing the jam.&lt;/p></description><content type="html"><![CDATA[<p>Participation in another game jam brings some thoughts on how to prepare properly.</p>
<p>Since I had my share of defeats as well as successful jams, I want to share my experience and lay down some things you can do to make the upcoming jam as smooth and productive, as possible.</p>
<p><img src="/img/2020/negative-laptop-notepad.jpeg" alt="Laptop and Notepad"></p>
<p>Jams, Sprints, and Hackathons are hyper-intensive events and you want to be ready beforehand.
Skipping preparations and just diving in can result in wasting valuable time, losing the flow, and even failing the jam.</p>
<p>So it might be a good idea to spend some time preparing.</p>
<h2 id="get-the-tools-ready">Get the Tools Ready</h2>
<p>First, you have to make sure that all your tools are in good shape.</p>
<p>The day before, update your software and check all the setup. It might seem to be a trivial issue, but it is not. In my experience, the team might lose valuable time fixing unexpected issues. Linux is mostly OK, but both Windows and macOS are notorious for that stupid &ldquo;reboot to update&rdquo; approach. Windows might even start the update automatically without confirmation. And you will end up with the &ldquo;Updating&hellip;&rdquo; logo instead of your favorite IDE.</p>
<p>You might think, things like that rarely happen. In fact, they happen all the time. It&rsquo;s just that we are not in a hurry to notice and be upset about it.</p>
<p>But in a jam or a hackathon, everything is happening so fast. And any distraction is a flow killer for the whole team.</p>
<p>Imagine, that you are on-site for jamming, Wi-Fi is not that good. And you are trying to update Homebrew or download hundreds of megabytes worth of plugins for your favorite IDE. Or register in Discord to join the team chat. Or figure out how to install drivers for your new Wacom tablet&hellip;</p>
<p>Make sure you&rsquo;ve done these things the day before, over the sweet home Wi-Fi.</p>
<h2 id="checklist-of-stuff-to-bring-along">Checklist of stuff to bring along.</h2>
<p>It is a good morning. I&rsquo;ve already had my breakfast. But I&rsquo;m in a hurry to skip the traffic and get to the jamming site earlier. I put a laptop, a charger, a phone, a notebook and a pen in my backpack.</p>
<p>And on a way to the parking lot, I suddenly stop. You know the feeling&hellip; I forgot the cable for the phone. Not a dealbreaker for a jam where you work only with a laptop - the phone is fully charged after all. But it is a mobile game jam and I need the cable to check the game on the phone. Now, I have to go back&hellip; And after that, I&rsquo;m stuck in a jam of the other kind - a traffic jam :)</p>
<p>When you are jamming on an external site, you have to bring everything you might need during the whole jam.</p>
<p><img src="/img/2020/chargers.jpeg" alt="Adapters"></p>
<p>Make a checklist and use it to pack the stuff. Mine usually looks like this:</p>
<h3 id="items-to-pack">Items to Pack</h3>
<ul>
<li>laptop</li>
<li>laptop charger</li>
<li>phone</li>
<li>phone charger</li>
<li>USB to USB Type-C cable</li>
<li>drawing tablet</li>
<li>brainstorming items
<ul>
<li>sheets of dotted paper</li>
<li>color stickers</li>
<li>a bunch of markers, pens, and pencils</li>
<li>various dices and tokens</li>
<li>a couple of RetroGamer issues for inspiration</li>
</ul>
</li>
<li>some snacks and water (if not provided on-site).</li>
</ul>
<h2 id="warm-up">Warm-up</h2>
<p>It is something I still fail to do all the time. And I think it is the most important of the bunch.</p>
<p>Warm-up sessions allow your team to setup and adjust the tools, establish means of communication and organization. It is an opportunity to discuss potential themes, styles, and game mechanics. And ideally, test-drive your tools.</p>
<p>Even if you plan to find your team on-site, you still have to make sure that you have installed everything that might be useful for communication with your future teammates. Again, you will avoid the download of Discord or Slack or Telegram distribution over the slow Wi-Fi.</p>
<p>The exact warm-up format may vary depending on a jam and personal goals.</p>
<p>Try to build an experimental prototype. Extend your toolbox with common library functions or typical code stubs. Sometimes, you can predict and mock-up generic features.</p>
<p>Before <a href="https://7drl.com/">7 Day Rogue Like Challenge</a>, I&rsquo;ve mocked up a text mode emulation and usage of Perlin noise to generate endless maps.</p>
<p>I&rsquo;ve experimented with platform physics, transitions, and menu systems while warming up for the last <a href="https://ldjam.com/">Ludum Dare</a>.</p>
<p>In mid-June, just before another hypercasual game jam, I&rsquo;ve spent a day with my teammate to create a VS Code autocomplete feature for <a href="http://collider.land">Collider.JAM</a>.</p>
<h2 id="eval-new-tech">Eval New Tech</h2>
<p>Some say you should never try unfamiliar tech during a jam. Stick to what you know.</p>
<p>I&rsquo;m not completely agree - it depends on your goals for that particular jam.</p>
<p>It is always risky, and some of my most spectacular failures happened when I decided to experiment with new tech.</p>
<p>But it can be a part of your personal goal. It is better to test out a tool during the warm-up. But a jam is a perfect opportunity to truly see the tool in the field - before you made any long-term commitments.</p>
<p>Just don&rsquo;t underestimate the effort required to handle a new tech. Don&rsquo;t try to experiment with other things at the same time - like an unfamiliar genre or experimental gameplay.</p>
<p>Make the project scope as microscopic, as possible. And then use the new tech to deliver it. You can extend the scope later if you&rsquo;ll have time left.</p>
<h2 id="explore-the-area">Explore the Area</h2>
<p>There is a benefit in preliminary exploring the area for on-site jams. Figure out how can you get there, where can you park, what facilities are available on-site.</p>
<p><img src="/img/2020/cafe-open.jpeg" alt="Open Sign"></p>
<p>Research the restaurants or food delivery nearby if needed. And sync-up with your team on food options.</p>
<h2 id="have-a-nice-jam">Have a Nice Jam!</h2>
<p>Following the advice above doesn&rsquo;t guarantee a successful jam, nor ensures that there won&rsquo;t be any problems.
But I&rsquo;ve found, that it makes my team much more effective and focused on delivering the prototype.</p>
<p>These techniques significantly reduce interruptions. And you should avoid interruptions at all costs. Since hyperfocus is the key ingredient for a successful jam.</p>
<p>Put additional effort to get your team in the zone, and in a couple of days, you will have an amazing prototype.</p>
<p>Good luck with your next jam!</p>
]]></content></item><item><title>Portability doesn't Come for Free</title><link>https://ikhotin.com/posts/2020/07/portability-doesnt-come-for-free/</link><pubDate>Wed, 08 Jul 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/07/portability-doesnt-come-for-free/</guid><description>&lt;p>Development Release 6 finally delivers stable Windows compatibility.&lt;/p>
&lt;p>&lt;a href="http://colliderlabs.com/jam">Collider.JAM&lt;/a> shell is based on &lt;a href="https://nodejs.org">Node.js&lt;/a> and it&amp;rsquo;s supposed to be portable&amp;hellip; In theory.
In practice, there are ALWAYS some issues.&lt;/p>
&lt;p>Since I haven&amp;rsquo;t been using Windows for the last 13 years or so, I didn&amp;rsquo;t have a machine suitable for proper testing. I guess it was working for some time&amp;hellip; Then I started to do some clever stuff with module scanning and unit discovery. And when you do something fancy with a filesystem, portability might suffer.&lt;/p></description><content type="html"><![CDATA[<p>Development Release 6 finally delivers stable Windows compatibility.</p>
<p><a href="http://colliderlabs.com/jam">Collider.JAM</a> shell is based on <a href="https://nodejs.org">Node.js</a> and it&rsquo;s supposed to be portable&hellip; In theory.
In practice, there are ALWAYS some issues.</p>
<p>Since I haven&rsquo;t been using Windows for the last 13 years or so, I didn&rsquo;t have a machine suitable for proper testing. I guess it was working for some time&hellip; Then I started to do some clever stuff with module scanning and unit discovery. And when you do something fancy with a filesystem, portability might suffer.</p>
<p>In our case, it was a little function responsible for mapping to a full path. It worked OK on Linux and MacOS, but failed to deliver a valid path on Windows.</p>
<p>DR6 is the first <a href="http://colliderlabs.com/jam">Collider.JAM</a> release evaluated with our new test set called Geneva. And I figured, it a nice opportunity to cover Windows support.</p>
<p>So I&rsquo;ve found a little Windows sticker on one of my Alienware Alphas, installed the OS along with Linux, and turned that machine into a test station. That allowed me to pinpoint and fix the bug on Windows.</p>
<p>Now that Alpha is dedicated to testing new releases. I can run tests against a git branch or a particular version from npm repo.</p>
<p>The only thing missing in this config is MacOS, and I still have to use an additional laptop to complete the portability test. Maybe a Mac Mini along with Alpha can be a solution to complete my testing stand?</p>
]]></content></item><item><title>On Collider.JAM DR4 Testing</title><link>https://ikhotin.com/posts/2020/05/on-collider.jam-dr4-testing/</link><pubDate>Wed, 27 May 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/05/on-collider.jam-dr4-testing/</guid><description>&lt;p>I&amp;rsquo;m thinking of testing automation for future releases of Collider.JAM. The initial DR4 package I&amp;rsquo;ve pushed to npm had broken dependencies. I&amp;rsquo;ve linked to the wrong tags and realized that only several days after. Since it kind of worked on my machine :)&lt;/p>
&lt;p>To avoid that in the future, more elaborated system is needed to check the release branch before a push. And the testing has to be done on a clean machine or inside a special Docker container.&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;m thinking of testing automation for future releases of Collider.JAM. The initial DR4 package I&rsquo;ve pushed to npm had broken dependencies. I&rsquo;ve linked to the wrong tags and realized that only several days after. Since it kind of worked on my machine :)</p>
<p>To avoid that in the future, more elaborated system is needed to check the release branch before a push. And the testing has to be done on a clean machine or inside a special Docker container.</p>
<p>Collider.JAM has a test engine implemented, but still no acceptance tests to validate a release. That is something to be delivered in the nearest Development Release to guaranty stability.</p>
<p>Being a solo developer working on the framework makes it hard to properly prioritize. What should come first? New exiting features, bug fixes, tooling, tests, documentation? Each is highly important. And for every release, I&rsquo;m trying to figure out the main focus. And only hope that my assumptions and priorities are right and that I&rsquo;m delivering a more polished and useful framework as a result.</p>
]]></content></item><item><title>Collider.JAM DR4</title><link>https://ikhotin.com/posts/2020/04/collider.jam-dr4/</link><pubDate>Thu, 30 Apr 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/04/collider.jam-dr4/</guid><description>&lt;p>&lt;em>&lt;a href="http://colliderlabs.com/jam/">Collider.JAM&lt;/a>
Development Release 4 is out!&lt;/em>&lt;/p>
&lt;p>I&amp;rsquo;ve completed major features for DR4 just before &lt;a href="https://ldjam.com/events/ludum-dare/46">Ludum Dare 46&lt;/a>. Only some minor fixes were included later.&lt;/p>
&lt;p>The jam itself is an adventure, that deserves it&amp;rsquo;s own post or two. I will definitely cover it in the future. Now I&amp;rsquo;m exhausted but quite satisfied with the results - &lt;a href="https://invadium.itch.io/station-keeping">a survival platformer on a space station with local co-op multiplayer&lt;/a>.&lt;/p>
&lt;p>In DR4 announce, I&amp;rsquo;d expected it would be possible to deliver the release somewhere before or after the jam. But a couple of sleepless nights and the following prostration made it impossible.&lt;/p></description><content type="html"><![CDATA[<p><em><a href="http://colliderlabs.com/jam/">Collider.JAM</a>
Development Release 4 is out!</em></p>
<p>I&rsquo;ve completed major features for DR4 just before <a href="https://ldjam.com/events/ludum-dare/46">Ludum Dare 46</a>. Only some minor fixes were included later.</p>
<p>The jam itself is an adventure, that deserves it&rsquo;s own post or two. I will definitely cover it in the future. Now I&rsquo;m exhausted but quite satisfied with the results - <a href="https://invadium.itch.io/station-keeping">a survival platformer on a space station with local co-op multiplayer</a>.</p>
<p>In DR4 announce, I&rsquo;d expected it would be possible to deliver the release somewhere before or after the jam. But a couple of sleepless nights and the following prostration made it impossible.</p>
<p>Now, I&rsquo;ve finished the major scope of post-jam activities. My game has already received 35 ratings, which qualifies it for the final score.</p>
<p>And I can finally focus on the release.</p>
<p>There is nothing big in DR4. However, a long list of various updates makes Collider.JAM closer to being a complete and finished product.</p>
<p>With DR4, you can spawn an entity from a state descriptor. So instead of a list of lab.spawn() calls somewhere in setup.js just put state descriptors in lab/ and they will be spawn automatically.</p>
<p>Now you can create custom post-processors for *.js and *.json files. Say, I want to post-process Ogmo tilemaps. To do that, I will create a function in <em>/lib/ext/ogmo.js</em> and now all *.ogmo.js files will be post-processed by that function when added to the mix.</p>
<p>The list of changes goes on and too long for a single post. You can run sketch mixes now, there are changes in how traps work, there are new ways to control mods, there is a new dynamic Z-ordering&hellip;</p>
<p>Now I will focus on tutorials to cover all these wonderful features.</p>
<p><em>Keep tuned and don&rsquo;t stop jamming!</em></p>
]]></content></item><item><title>Collider.JAM DR3</title><link>https://ikhotin.com/posts/2020/04/collider.jam-dr3/</link><pubDate>Tue, 07 Apr 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/04/collider.jam-dr3/</guid><description>&lt;p>&lt;em>&lt;a href="http://colliderlabs.com/jam/">Collider.JAM&lt;/a>
Development Release 3 is out!&lt;/em>&lt;/p>
&lt;p>Main achievements are pretty simple - F1 and F2.&lt;/p>
&lt;p>Readme and man pages have been updated.
By pressing F1, you are getting much better info now.
But tutorials are still missing,
and that is something to fix in future releases.&lt;/p>
&lt;p>Node Inspector is available by pressing F2.
It has also been greatly improved.
Back action works as expected
and there is a proper sync between tabs.&lt;/p></description><content type="html"><![CDATA[<p><em><a href="http://colliderlabs.com/jam/">Collider.JAM</a>
Development Release 3 is out!</em></p>
<p>Main achievements are pretty simple - F1 and F2.</p>
<p>Readme and man pages have been updated.
By pressing F1, you are getting much better info now.
But tutorials are still missing,
and that is something to fix in future releases.</p>
<p>Node Inspector is available by pressing F2.
It has also been greatly improved.
Back action works as expected
and there is a proper sync between tabs.</p>
<p>The taken multi-tab approach has good usage
potential - not just plain node exploration.
I&rsquo;m thinking about copy/spawn features,
search, and node modifications here.</p>
<hr>
<p>I&rsquo;ve managed to deliver that release in a month
(and not in 6 like DR2).
Now, I&rsquo;m declaring a more ambitious target -
make DR4 in just 2 weeks.
<a href="https://ldjam.com/events/ludum-dare/46">Ludum Dare 46</a>
is coming in the middle of April 2020
and that is a perfect deadline for the next Development Release.</p>
<hr>
<p>So keep quarantine and don&rsquo;t stop jamming!</p>
<p>New amazing features are coming!</p>
]]></content></item><item><title>Hello Human</title><link>https://ikhotin.com/posts/2020/03/hello-human/</link><pubDate>Fri, 27 Mar 2020 00:00:00 +0000</pubDate><author>khotin@gmx.com (Igor Khotin)</author><guid>https://ikhotin.com/posts/2020/03/hello-human/</guid><description>&lt;h2 id="it-is-time-for-a-new-blog">It is time for a new blog!&lt;/h2>
&lt;p>I&amp;rsquo;ve been using blogger.com for many years.
Though not a productive blogger,
I&amp;rsquo;ve been posting now and then.&lt;/p>
&lt;p>For &lt;a href="http://invasionwave.com">invasionwave.com&lt;/a>
and &lt;a href="http://invaderslounge.com">invaderslounge.com&lt;/a>
I&amp;rsquo;ve decided to go with Wordpress.
A lot of features, but also a lot of hustle to maintain.&lt;/p>
&lt;p>I don&amp;rsquo;t need any fancy plugins for my personal page.
All I need is a simple way to turn markdown
into HTML pages.&lt;/p>
&lt;p>Therefore, this site is running on Hugo - simple and powerful
static site generator written in Go.&lt;/p></description><content type="html"><![CDATA[<h2 id="it-is-time-for-a-new-blog">It is time for a new blog!</h2>
<p>I&rsquo;ve been using blogger.com for many years.
Though not a productive blogger,
I&rsquo;ve been posting now and then.</p>
<p>For <a href="http://invasionwave.com">invasionwave.com</a>
and <a href="http://invaderslounge.com">invaderslounge.com</a>
I&rsquo;ve decided to go with Wordpress.
A lot of features, but also a lot of hustle to maintain.</p>
<p>I don&rsquo;t need any fancy plugins for my personal page.
All I need is a simple way to turn markdown
into HTML pages.</p>
<p>Therefore, this site is running on Hugo - simple and powerful
static site generator written in Go.</p>
<p>I&rsquo;m still figuring out how to do some stuff,
but the overall impressions are good.
It is simple and text-file oriented.
An ideal choice for a unix plumber and a vim aficionado like me.</p>
<p>See you soon!</p>
]]></content></item></channel></rss>