[{"content":"Every new era brings its own set of pros and cons. Sometimes the balance between them really matters. What I want to talk about here is one of the discouraging effects AI has on us engineers today.\nAI has brought major changes. With AI editors, we can finish boring tasks very quickly. Even people who do not know how to code can now show impressive demos online through vibe coding. This is all great. Everything is faster and more accessible. On paper, it feels like we have already won. But what have we lost?\nIf we think back to software development before AI, the workflow was different. We relied heavily on search engines. We did long research sessions for a feature or a bug fix. We jumped from site to site, collected hints, and followed trails. Not every problem had a simple answer. It felt like detective work.\nI still think of software engineering as a kind of detective work. You gather as much material as possible, then you act. This is still true today, but the scale has changed. There was also another side to these practices: communication with other people. When we ran into a problem, we would ask questions on forums. Anyone remember Stack Overflow? We asked for help. Sometimes we were mocked for asking simple questions, but that was part of it. Through comments and discussions, you could directly interact with engineers who were actively working in the field. It gave us a chance to meet people who were really good at what they did. I cannot say this is completely gone today, but it is clearly fading. In a world that is becoming more individualistic, this has become even more so. I still remember the joy of finding the correct answer hidden between small comments on Stack Overflow.\nWhen we worked in offices, if we had a problem, we would go to a colleague’s desk and think it through together. Now we prefer asking an LLM. Ask and move on. It is fast. It feels rewarding. A quick hit for the dopamine receptors.\nI wonder what kinds of opportunities we are starting to miss. Meeting new people? The unexpected opportunities that might come from those meetings? I do not have an answer yet.\nIn May 2021, someone named David Dohan reached out to me on Twitter. At the time, he was an engineer at Google DeepMind. I had recently published a ClojureScript library called re-frame-flow. David liked the library a lot and asked me for ClojureScript consulting. He was working on a kind of Clojure and React flowchart-style application and needed extra help. We then spent nearly two hours on a consulting session and solved his problem. It was a great session. Helping such a smart engineer was a really nice experience. I suspect that today, if he needed help, he would just ask an LLM and move on, and this connection would never have happened. These kinds of encounters could have led to great beginnings, but AI may be quietly cutting off that path.\nWhat I am saying is this: every new innovation will take some things away while bringing others. I just hope we do not start regretting what it takes from us.\n","permalink":"https://ertu.dev/posts/ai-is-killing-our-online-interaction/","summary":"\u003cp\u003eEvery new era brings its own set of pros and cons. Sometimes the balance between them really matters. What I want to talk about here is one of the discouraging effects AI has on us engineers today.\u003c/p\u003e\n\u003cp\u003eAI has brought major changes. With AI editors, we can finish boring tasks very quickly. Even people who do not know how to code can now show impressive demos online through vibe coding. This is all great. Everything is faster and more accessible. On paper, it feels like we have already won. But what have we lost?\u003c/p\u003e","title":"AI is killing our online interaction"},{"content":"Sometimes, in the middle of life, out of nowhere, random snapshots from the past pop into our minds. It could happen while walking, reading a book, or watching a view. For me, it usually happens when I’m coding or looking at a landscape. This time, while I was coding, a snapshot from more than 20 years ago came to mind.\nI was a kid, maybe around ten. We had a music CD at home. This was the late ’90s or early 2000s, so we used Sony Walkmans to listen to music. I really liked that CD back then, but I couldn’t remember its name or the cover clearly, just some blurry fragments. A few words stuck in my mind: “Webb” and “Ocean.” These two were clear. I immediately started searching online, hoping to find a digital version. But the deeper I looked, the more surprising the result was: absolutely nothing. It was like the internet had forgotten it. Search engines only showed recent, popular content. It felt like they had erased the past.\nI only found a couple of old sites that mentioned the album’s release year and the production company. At least that was something. The album came out in 1998, so I figured it wasn’t digitized because it never got enough attention, and that’s perfectly fine. The CD originated from Spain, which surprised me because the singer’s voice had an American accent (as far as I remember). That might be why my initial searches led nowhere. I was only looking for American or British artists.\nI decided to email the production company I found, but I think I contacted the wrong one. They never replied. Maybe they had already shut down. Later, I discovered the album’s name: Broken Ocean. I searched for “Webb - Broken Ocean” online and, boom! Someone was selling a physical copy on eBay. I was over the moon. As soon as I saw the cover, I recognized it instantly. I ordered it right away.\nTwo weeks later, the CD arrived by post. It came from Spain. I was filled with a deep, nostalgic feeling. Opening that package made me feel like I was time-traveling.\nThere’s another piece I haven’t mentioned. A few weeks before I even thought about this album, my parents had sent some photos to our family WhatsApp group. They were doing some cleaning at the old house and shared pictures of things from our childhood. Among them was our old Walkman. I didn’t think much of it at the time, but I’m pretty sure that image triggered the memory. I used to listen to Webb with that exact Walkman.\nA few days before the CD arrived, I asked my parents to bring me the Walkman, and they did. So, let’s jump to that moment. I was holding the CD in my hands, the Walkman in front of me. I carefully opened the lid, placed the CD inside, closed it, and hit play. It didn’t work. I tried again - still nothing. Turns out you had to hold the play button. And then… the sound. That was it. That’s what I had been looking for.\nI was in a trance for the first five tracks. It was like a wave of emotions and memories flooding my brain. Of course, the Walkman is very old now, so the sound was full of static, but I didn’t care. In that moment, everything else faded away. I decided to digitize the tracks. I ordered an external CD-ROM right away.\nWhile waiting for it to arrive, my sister called and invited us to her child’s first birthday. My wife and I said yes, and we flew from Istanbul to Antalya before the CD-ROM arrived.\nWe got there on April 30. After a big family breakfast, I showed my sister the CD. I asked her, “Do you remember this? We had it when we were kids.” She smiled and said, “I remember it clearly!” I didn’t expect that. Maybe the album pulled her briefly into the past too. I’m pretty sure she didn’t really listen to it back then, maybe just saw it around the house or heard me play it. I told her the whole story, and she listened with interest.\nLater, after everyone had spread out around the house, my parents with the grandkids, my sister and wife chatting over coffee, and my brother-in-law out at work. I sat with my laptop and started digging deeper. On the back of the CD, I noticed two names: Oscar Palop and Jordi Mesia. I searched for them to see if they had done other music.\nI couldn’t find much until I stumbled upon a Facebook profile for someone named Oscar Palop. Most of his posts were art-related: drawings, paintings, modern art. Nothing about music.\nI almost gave up, thinking it wasn’t him. But then I saw a drawing in black and white, made of line figures. It looked exactly like the figures on the CD cover. I compared it right away and thought, if this Oscar Palop isn’t the Oscar Palop, then no one is. I might as well take my shot and reach out, what do I have to lose?\nLuckily, his email was listed on his page. I attached a photo of the CD cover and wrote:\nWhen I was a kid, there was a music CD in our home from Webb - Broken Ocean. When I searched online, I couldn’t find it. There is no digital version. I saw a name on the back of the CD - Oscar Palop. Is this you?\nThe next morning at 9:30, I got a reply. The whole conversation happened in Spanish (thanks, technology).\nOscar Palop:\nYes, Broken Ocean is indeed a \u0026lsquo;98 album, and my name is Oscar Palop. From what I understand, you\u0026rsquo;re probably from Turkey. I had a good friend in Istanbul, Ertugrul Sener. I don\u0026rsquo;t know if you have anything in common, but I\u0026rsquo;d like to know how you got the CD and if I can help you with anything. Best regards.\nMe:\nHello again, yes, I’m reaching out from Istanbul, Turkey. I don’t know Ertugrul Sener, I’m Ertugrul Cetin. Is he a famous artist?\nThe Broken Ocean CD was in our old house when I was a child, and I loved it. I don’t know how it ended up in our home; I think it was more than 25 years ago, maybe in the early 2000s. In recent weeks, the CD came to my mind - I’m 33 now and for some reason, I started searching for it online. The only words I remembered were “Webb” and “Ocean.” By chance, someone in Spain was selling it in CD format, and I immediately ordered it on eBay. It arrived a few days ago, and I was so happy.\nThen I found the names of the composers and creators in the CD booklet: Oscar Palop and Jordi Mesia. I couldn’t find much information online, so I reached out to ask if you were the one who made it, because it’s truly a beautiful album. If I’m not mistaken, you are the Oscar Palop mentioned, right?\nOscar Palop:\nYes, I\u0026rsquo;m Oscar Palop, composer of all the songs, singer, and keyboardist. Jordi Mesiá passed away about 10 years ago. We created Webb in the late 70s. From 82 to 87, Webb was a four-piece progressive rock band. We met and continued with Mesia (guitar and sound engineering expert) until 2015 when he fell ill.\nMe:\nI understand, thank you very much for the information. You truly made a beautiful album - it was way ahead of its time, real music. I’m sorry for the loss of your friend. Are you still making music? I saw on your Facebook page that you’re more focused on art-related work now. Also, if you give me your permission, I’d love to digitize these songs from the CD and upload them somewhere like YouTube so they won’t be lost and can stay alive.\nOscar Palop:\nThank you for your kind words. I\u0026rsquo;ve composed a ton of music. Custom songs, wedding music, music for books and film projects, and songs as if the band still existed. I don\u0026rsquo;t mind if you upload the songs, although I have most of them digitized. All of them, even those not on Broken Ocean, are registered, as I\u0026rsquo;m a member of SGAE, the General Society of Spanish Authors. You can count on me for anything I can help you with. Music, along with painting and poetry, are my hobbies. My profession is Industrial Engineer. I remain at your disposal.\nMe:\nYou’re very thoughtful, thank you so much. By the way, I’m also an industrial engineer, a nice coincidence. Although I work in tech. If you have digital versions of the songs from the Broken Ocean album, I’d love to receive them through a link. If not, I’ll buy an external CD reader and digitize them myself in the coming days.\nOscar Palop:\nWell, I don\u0026rsquo;t have all the tracks on the CD, but almost all of them. I can send them to you via Gmail. I\u0026rsquo;ll tell you why each track has a reason, if it helps you post it on YouTube.\nMe:\nSure, that would be great. You can send them to me via Gmail whenever you can, thank you so much!\nMe:\nThank you very much, I have the songs. I just downloaded them from WeTransfer.\nOscar Palop:\nI’ve been informed that you’ve downloaded the songs I sent you. As I mentioned, here’s a very brief explanation of what each one is about: 1. At the Threshold – I was at a decisive moment in choosing Zen philosophy once and for all. 2. Broken Ocean – The lyrics were written while returning from a trip to China, flying over the Gobi Desert. From the air, the desert feels like a broken ocean. 3. Drawn in my Heart – A song dedicated to a partner, who is now a great friend. 4. I Trust – About a person who is blind and hopes to see the light someday. 5. Prayer to the Wind – Lyrics about personal growth and finding oneself. 6. Shades of Hope – A true story about the disappearance of a girl named Mary and her father’s anguish as he searched for her. 7. Uncertain Fates – Dedicated to African peoples oppressed by corrupt politicians. Still missing: 1. Wild Life – Dedicated to the Lakota (Sioux) people and their extermination. 2. Blue Glance Movie – A critique of our drummer’s wife. 3. Crazy – The crazy things you do that sometimes hurt people who leave you, and then you regret losing them. 4. Hot Rain – After many trips, the longing to return home, only to create more humanitarian songs and leave again. If you have any questions, don’t hesitate to contact me. Note: For any publication you make, please remember the copyright, as SGAE finds out everything. Me:\nIt’s truly inspiring. There aren’t enough words to thank you for sharing the meaning behind your songs. There’s such interesting information. It’s a special feeling to be able to speak with a true artist. If you’d like, after I digitize the remaining tracks, I can send them to you as well. And don’t worry about the copyright. I just want these beautiful pieces to exist in digital format to preserve them. They can inspire and bring joy to others, just as they did to me.\n10 Days later..\nMe:\nHi Oscar, I recently got hold of the CD-ROM and converted the remaining 4 songs to digital format. I’ve created a YouTube playlist that includes all the tracks from the album. Under each video, I added the title, your name and Jordi Mesia’s, and the lyrics. Also, on the main page of the playlist, I listed the names of all the people mentioned in the album, exactly as they appear on the CD cover. Here’s the link to the playlist: https://www.youtube.com/playlist?list=PLiDUKXlPu2kz_0ECW1dbL2EzJovkNTok3 Thank you so much for letting me upload the videos.\nThanks to all this, I got the chance to connect with someone who had touched lives through music and art. It was a short journey, but full of meaning, excitement, and nostalgia. In a time when everything moves so fast, this little pause reminded me how beautiful it is to revisit the past, even for just a moment.\n","permalink":"https://ertu.dev/posts/a-snaphot-from-the-walkman-era/","summary":"\u003cp\u003eSometimes, in the middle of life, out of nowhere, random snapshots from the past pop into our minds. It could happen while\nwalking, reading a book, or watching a view. For me, it usually happens when I’m coding or looking at a landscape. This time,\nwhile I was coding, a snapshot from more than 20 years ago came to mind.\u003c/p\u003e\n\u003cp\u003eI was a kid, maybe around ten. We had a music CD at home. This was the late ’90s or early 2000s, so we used Sony Walkmans to\nlisten to music. I really liked that CD back then, but I couldn’t remember its name or the cover clearly, just some blurry\nfragments. A few words stuck in my mind: “Webb” and “Ocean.” These two were clear. I immediately started searching online, hoping\nto find a digital version. But the deeper I looked, the more surprising the result was: absolutely nothing. It was like the\ninternet had forgotten it. Search engines only showed recent, popular content. It felt like they had erased the past.\u003c/p\u003e","title":"A snapshot from the Walkman era"},{"content":"Developing a multiplayer third-person shooter game as a solo developer is a journey filled with challenges and rewards. I embarked on this adventure to create Wizard Masters, a web-based multiplayer game where players battle as mages wielding elemental spells.\nBuilt using Clojure, a Lisp dialect, this project pushed the boundaries of web game development and my own skills as a programmer. Here’s how it went.\nIn Wizard Masters, players can choose from six elemental spells—fire, toxic, ice, lightning, and earth—and compete in two modes: solo and team deathmatch. I published the game on CrazyGames to reach a broader audience. However, its multiplayer nature demanded a large player base, which was a constant challenge.\nGitHub Link: https://github.com/ertugrulcetin/wizard-masters\nWhy Clojure? Clojure is my go-to programming language, both professionally and personally. It’s a full-stack language:\nClojure runs on the JVM for backend development. ClojureScript compiles to JavaScript, enabling smooth browser-based applications. This one language to rule them all approach made it an obvious choice for me. Additionally, Clojure’s REPL ( Read-Eval-Print Loop) system is a game-changer. Unlike typical REPLs, Clojure’s REPL is highly interactive and organic, allowing live updates to the game without refreshing the browser. This significantly sped up my development process, enabling me to create and test mechanics in real time.\nI created a YouTube video showing how to use the REPL with jMonkeyEngine, a Java-based game framework. You can watch it here.\nGraphics Library After experimenting with several graphics libraries, including Three.js and PlayCanvas, I chose Babylon.js. Here’s why:\nFeature-rich: Babylon.js offers a robust set of tools for 3D development. Great documentation: Compared to other libraries, Babylon’s documentation stands out for its clarity and comprehensiveness. Supportive community: The community’s assistance proved invaluable. ClojureScript’s npm integration through shadow-cljs made it easy to incorporate Babylon.js, allowing me to focus on building the game.\nCode The following code snippet showcases the implementation of a :player/jump rule, which handles the player’s ability to jump in the game. This rule uses a :what block, essentially a hashmap, to define the conditions under which the rule is triggered.\nIn Wizard Masters, all game data resides in a global game database—a single large hashmap. The fields referenced in the :what block (e.g., :pointer-locked?, :player/ground?) are keys in this global hashmap. To execute the rule, several conditions must be met:\nEach key in the :what block must have a non-null value. The :when block must evaluate to true. The :then block is executed when the above conditions are satisfied. The triggering of this rule occurs through the fire-rules function, which activates the rule whenever a :what field is updated, regardless of whether the value changes. If a field has a :then false attribute, the rule will not trigger, avoiding infinite loops and unnecessary executions. The rule system was influenced by the Clojure library O’Doyle Rules by Zach Oakes.\nHere’s the complete implementation for the :player/jump rule:\n(reg-rule :player/jump {:locals {:jump-vec (v3)} :what {:keys-pressed {} :player/mobile-jump-click? {} :pointer-locked? {:then false} :player/ground? {:then false} :player/capsule {:then false} :player/anim-groups {:then false} :keys-was-pressed {:then false} :player/jump-up? {:then false}} :when (fn [{{:keys [player/game-started? player/mobile-jump-click? player/ground? player/dash? player/jump-up? player/current-running-anim-group player/current-health]} :session}] (and game-started? (nil? current-running-anim-group) (or (re/key-is-pressed? \u0026#34;Space\u0026#34;) mobile-jump-click?) ground? (not (freezing?)) (not (wind-stunned?)) (not jump-up?) (not dash?) (\u0026gt; current-health 0))) :then (fn [{{player-capsule :player/capsule player-jump-force :player/jump-force} :session {:keys [jump-vec]} :locals}] (j/assoc! jump-vec :y player-jump-force) (when-not (casting-spell?) (re/fire-rules {:player/jump-up? true})) (let [player-pos (api.core/get-pos player-capsule)] (api.physics/apply-impulse player-capsule jump-vec player-pos)))}) How It Works :what block defines dependencies, such as key presses and the character’s physical capsule etc. :when block ensures the jump can only occur under certain conditions (e.g., the player isn’t frozen or stunned). :then block applies an upward force to the player’s capsule and triggers additional rules if needed. The next example demonstrates a rule for updating the player’s rotation every frame. This ensures the character always faces the forward direction of the camera. Here, the dt field in the :what block represents the time elapsed between the current frame and the previous one, causing the rule to trigger on every frame.\n(reg-rule :player/rotation {:locals {:forward-temp (v3) :result-temp (v3)} :what {:dt {} :camera {} :player/model {}} :when (fn [{{:keys [player/game-started?]} :session}] game-started?) :then (fn [{{camera :camera player-model :player/model} :session {:keys [forward-temp result-temp]} :locals}] (let [[yaw offset] (api.camera/get-char-forward-dir {:camera camera :forward-temp forward-temp :result-temp result-temp})] (m/assoc! player-model :rotation.y (+ yaw offset))))}) Network Writing network code for a fast-paced multiplayer game was a monumental task. I initially chose to handle all the networking myself, thinking it would be a rewarding experience. It was indeed rewarding—but also hellish. I used several Clojure async libraries, including Aleph, Manifold, and core.async, to manage the complexity of real-time communication.\nWhen a player joins a game, a WebSocket connection is established. The backend continuously sends world snapshots to all connected players at a tick rate of 20 (one update every 50 milliseconds). Additionally, specific processes handle actions like spellcasting, damage calculation, and player deaths.\nThe following snippet registers a process called :super-nova, which handles the logic for a player casting a Super Nova spell. When triggered, the backend processes the event asynchronously, computes the area of effect, and notifies relevant players.\n(reg-pro :super-nova (fn [{:keys [id data]}] (try (add-super-nova id (:pos data)) ;; Add the visual effect (apply-range-damage {:current-player-id id :pos (:pos data) :radius super-nova-range :diameter super-nova-diameter :max-damage 600 :damage-pro-id :got-super-nova-hit}) ;; Calculate damage (catch Exception e (log/error e \u0026#34;Super nova hit error!\u0026#34;))))) Area of Effect Damage Calculation The core of this process is the apply-range-damage function. This function determines which players are affected by a spell, calculates the damage based on proximity, and updates the game state accordingly.\n(defn- apply-range-damage [{:keys [current-player-id pos radius height diameter max-damage damage-pro-id shape-type damage-over-time damage-params] :or {shape-type :sphere}}] (when-let [room-id (get-room-id-by-player-id current-player-id)] (let [current-player-ids (set (keys (get-players-with-same-room-id current-player-id))) my-team (get-player-team current-player-id) players-within-range (-\u0026gt;\u0026gt; (get-world-by-player-id current-player-id) (keep (fn [[player-id player-data]] (let [[x y z] [(:px player-data) (:py player-data) (:pz player-data)] [x1 y1 z1] pos player-distance (distance x x1 y y1 z z1) within-range? (if (= shape-type :cylinder) (within-cylinder? pos [x y z] radius height) (\u0026lt;= player-distance radius))] (when (and (not= player-id current-player-id) (current-player-ids player-id) (enemy? room-id player-id my-team) (\u0026gt; (:health player-data) 0) (:focus? player-data) within-range?) [player-id player-distance]))))) damage-and-positions (for [[player-id distance] players-within-range :let [damage (generate-damage {:distance distance :max-damage max-damage :area-of-affect-diameter diameter :shape-type shape-type}) damage (get-damage-for-player damage current-player-id player-id)] :when (\u0026gt; damage 0)] (let [world (swap! world (fn [world] (let [health (max 0 (- (get-in world [room-id player-id :health]) damage)) died? (= 0 health) world (assoc-in world [room-id player-id :health] health)] (if died? (assoc-in world [room-id player-id :st] \u0026#34;die\u0026#34;) world)))) died? (= 0 (get-in world [room-id player-id :health]))] (when died? (update-stats-after-death current-player-id player-id)) (send! player-id damage-pro-id (merge {:player-id current-player-id :damage damage :died? died?} damage-params)) (update-last-damage-time player-id) (add-damage-effect player-id (if (= damage-pro-id :got-ice-tornado-hit) :ice :fire)) [player-id damage died?]))] (when damage-over-time (register-enemies-for-damage-over-time (now) current-player-id room-id damage-over-time (map first players-within-range))) {:damage-and-positions damage-and-positions}))) The process begins by filtering players to identify those in the same room, excluding teammates, and checking if they are within the spell’s radius or cylindrical area. Once the affected players are identified, the damage is calculated, decreasing with distance from the spell’s origin while ensuring it is positive and does not exceed a player’s current health. Finally, the game state is updated by deducting the damage from each player’s health, marking players as “dead” if their health reaches zero, notifying affected players of the damage, and updating the attacker’s stats accordingly.\nThe backend handles real-time complexity by continuously updating multiple players and ensuring synchronization across all devices. Events such as spellcasting and deaths are processed asynchronously through queues to maintain performance. Developing custom networking code from scratch was both challenging and educational, offering valuable insights into the trade-offs between control and complexity.\nThe Journey At the beginning of my game development journey, everything felt fantastic. I was quickly iterating through features, mechanics, and UI development, making substantial progress in short bursts. However, as the project grew, it became increasingly challenging to manage. The difficulty wasn’t directly tied to Clojure’s nature—there were many other contributing factors.\nGame development is fundamentally an art of state management. States are everywhere, and managing numerous unrelated systems in harmony is a challenging task. While Clojure’s immutability by default offers many advantages, it also introduces complexity. To handle the intricate state management required for game development, I had to create my own abstractions. Writing a custom DSL (domain-specific language) became a necessity, but it wasn’t easy.\nAdding to the challenge was the lack of a strong Clojure game development community. While Clojure excels in domains like SaaS products and finance, its adoption in game development is virtually nonexistent. The absence of shared tools, libraries, and best practices in this space made the journey even more isolating.\nI couldn’t help but feel envious of the tooling ecosystems surrounding major game engines like Unity and Unreal Engine. While Babylon.js is a great library, it lacks the robust plugin ecosystems, frameworks, and tools that mainstream engines offer. Developing with Babylon.js often meant building tools from scratch. While this taught me a lot about graphics programming, it came at the cost of time—a critical resource in modern game development.\nGood tooling is a cornerstone of game development today. The lack of it left me feeling perpetually one step behind.\nDeveloping 3D games for the web comes with inherent limitations. While WebGL has improved significantly, and WebGPU is on the horizon, web-based games are still far behind native games in terms of performance and graphical fidelity. These limitations force developers to make compromises.\nResource constraints on the web are another hurdle. Users expect quick load times and minimal downloads. Asking players to wait for a 500MB download before they can play is unrealistic. This restricts web games to being small, free, and often simplistic. The result? Web games rarely rival the scale or polish of PC or console games.\nFinancially, web game development doesn’t make much sense. Monetization options are limited, with ads being the primary choice. But ads disrupt immersion and often force you to design your game around them just to earn a modest income.\nThe web game market is tiny compared to PC and console markets. While there are a few success stories like Agar.io and Wordle. Only a couple of major web game publishers, like CrazyGames and Poki, exist. Rejection from these platforms can make it nearly impossible to reach a large audience. To sustain yourself financially, you’d need to create a high volume of games in a short period, which is neither practical nor creatively satisfying.\nThe one advantage web games have is ease of distribution. Sharing a link is all it takes for anyone to jump in and start playing. But this strength alone doesn’t compensate for the many weaknesses.\nMaking a game is hard; making a successful game is even harder. Creating a good game is like cooking a great meal—you can do wonders with a handful of ingredients or fail miserably with a dozen. There’s no single formula for success. Everything needs to align: timing, optimization, art, sound, trends, and theme.\nA few years ago, the battle royale trend exploded, leading to a flood of games trying to capitalize on the craze. Even great games like Spellbreak couldn’t sustain themselves. But following trends isn’t inherently bad; it’s about execution. If done well, it can be a smart business move.\nFinal Thoughts Game development is a deeply rewarding yet demanding journey. Whether you’re building games with unconventional tools like Clojure or navigating the limitations of web platforms, the challenges are immense. I’ve learned several key lessons.\nFirst, web games are fantastic for prototyping thanks to their ease of distribution, but resource constraints make them unsuitable for larger projects.\nSecond, Clojure’s REPL and functional paradigm enabled rapid iteration, but its niche nature and lack of game development resources added unnecessary difficulty.\nLastly, tooling is crucial—while building custom tools taught me a lot, the absence of robust, ready-made tools significantly slowed progress. Moving forward, transitioning to a mainstream engine like Unity or Unreal could streamline development and allow me to focus more on the creative aspects of game design.\nUltimately, the act of creating games—bringing ideas to life—remains an unparalleled experience, with each challenge offering invaluable lessons.\nIt’s not just about the end result but the lessons learned along the way.\n","permalink":"https://ertu.dev/posts/i-made-an-online-shooter-game-in-lisp/","summary":"\u003cp\u003eDeveloping a multiplayer third-person shooter game as a solo developer is a journey filled with challenges and\nrewards. I embarked on this adventure to create \u003cstrong\u003eWizard Masters\u003c/strong\u003e, a web-based multiplayer game where players battle as\nmages wielding elemental spells.\u003c/p\u003e\n\u003cp\u003eBuilt using \u003cstrong\u003eClojure\u003c/strong\u003e, a Lisp dialect, this project pushed the boundaries of web game\ndevelopment and my own skills as a programmer. Here’s how it went.\u003c/p\u003e\n\u003cp\u003eIn Wizard Masters, players can choose from six elemental spells—fire, toxic, ice, lightning, and earth—and compete in\ntwo modes: solo and team deathmatch. I published the game on CrazyGames to reach a broader audience. However, its\nmultiplayer nature demanded a large player base, which was a constant challenge.\u003c/p\u003e","title":"I made a multiplayer shooter game in Lisp"}]