<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog</title><description>Home</description><link>https://blog.catboy.best/</link><language>en</language><item><title>Xcyte</title><link>https://blog.catboy.best/posts/xcyting/</link><guid isPermaLink="true">https://blog.catboy.best/posts/xcyting/</guid><description>The Pokémon X/Y Project</description><pubDate>Sun, 09 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This Project is designed to be for all types of players. From players who never played the game to players who developed a deep knowledge for the game. The primary goal is to enjoy the gameplay and to experience the joy of playing the game, trade Pokémon and to battle with other players! Since the newest game (Pokémon Legends Z-A) is playing in the same region as generation 6, we&apos;re playing the original: X/Y.&lt;/p&gt;
&lt;h3&gt;How does all of this go?&lt;/h3&gt;
&lt;h4&gt;Registrations&lt;/h4&gt;
&lt;p&gt;Registrations close on &lt;strong&gt;23.01.2026 - 23:59&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Participants&lt;/h4&gt;
&lt;p&gt;Participants will be announced on &lt;strong&gt;26.01.2026&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Start&lt;/h4&gt;
&lt;p&gt;The project will officially begin on the evening of &lt;strong&gt;30.01.2026&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Tournament&lt;/h4&gt;
&lt;p&gt;The tournament will take place on the weekends between &lt;strong&gt;27.02.2026 - 29.03.2026&lt;/strong&gt;. This gives everyone 4 weeks to prepare.&lt;/p&gt;
&lt;h3&gt;What if I don&apos;t stream?&lt;/h3&gt;
&lt;p&gt;Every streamer who gets selected will receive their own team that viewers can register for to play along.
These teams will also compete in a league table at the end to earn points.&lt;/p&gt;
&lt;h3&gt;Where do I register?&lt;/h3&gt;
&lt;p&gt;Over this form: https://docs.google.com/forms/d/1rReyeOqfujPxCIsqXibnHvK54hdVzhMUfMV4rQIcLoo/edit?pli=1&lt;/p&gt;
&lt;p&gt;Additionally, you can join onto this Discord Server if you&apos;re interested: https://discord.gg/SncBqdkQ2V&lt;/p&gt;
&lt;p&gt;Choose your roles and you’re good to go!&lt;/p&gt;
&lt;h3&gt;What do I need to be able to participate?&lt;/h3&gt;
&lt;h4&gt;Emulator&lt;/h4&gt;
&lt;p&gt;We&apos;re using the &lt;strong&gt;Azahar Emulator&lt;/strong&gt;, as it is required for tools like Pokélink.&lt;/p&gt;
&lt;h4&gt;Pokélink&lt;/h4&gt;
&lt;p&gt;If you are a streamer, we need Pokélink so we can keep track of your team and progress.&lt;/p&gt;
&lt;h4&gt;The Game &amp;amp; Setup&lt;/h4&gt;
&lt;p&gt;After registrations close, we will provide help on the Discord server.&lt;/p&gt;
&lt;h3&gt;Rules when playing&lt;/h3&gt;
&lt;h4&gt;Emulator Speed&lt;/h4&gt;
&lt;p&gt;Anything between &lt;strong&gt;100-200%&lt;/strong&gt; is allowed.&lt;/p&gt;
&lt;h4&gt;Cheats&lt;/h4&gt;
&lt;p&gt;All forms of cheats are strictly forbidden.&lt;/p&gt;
&lt;h4&gt;Pokémon&lt;/h4&gt;
&lt;p&gt;In your solo gameplay, you may use any Pokémon you feel fits your playstyle or asthetic.&lt;/p&gt;
&lt;p&gt;Please use common sense when choosing names, avoid anything inappropriate.&lt;/p&gt;
&lt;h4&gt;Trading&lt;/h4&gt;
&lt;p&gt;Trading is fully allowed and encouraged between all players!&lt;/p&gt;
&lt;h4&gt;Battles&lt;/h4&gt;
&lt;p&gt;Test battles are allowed for training and to familiarize yourself with the battle rules.&lt;/p&gt;
&lt;h3&gt;Rules for Battle&lt;/h3&gt;
&lt;h4&gt;Qualification&lt;/h4&gt;
&lt;p&gt;You qualify to participate by becoming the Champion of the Pokémon region.&lt;/p&gt;
&lt;h4&gt;Format&lt;/h4&gt;
&lt;p&gt;Single Battle (1v1) with 6 Pokémon, all automatically set to Level 50. Pokémon must be unique. No duplicates of the same Pokémon species.&lt;/p&gt;
&lt;h4&gt;Mega Evolution&lt;/h4&gt;
&lt;p&gt;Mega Evolution is only allowed if both players are able to use Mega Evolution on a Pokémon.&lt;/p&gt;
&lt;h4&gt;Legendaries&lt;/h4&gt;
&lt;p&gt;Legenderies are not allowed&lt;/p&gt;
&lt;p&gt;Pseudo-Legendaries (like Garchomp or Dragonite) are allowed.&lt;/p&gt;
&lt;h4&gt;Items&lt;/h4&gt;
&lt;p&gt;While Items are allowed to be held by Pokémon, using anything in active battle (like Potions) are not allowed.&lt;/p&gt;
&lt;h4&gt;Cheat Sheets&lt;/h4&gt;
&lt;p&gt;You are allowed to keep an open type chart to check effectiveness if needed.&lt;/p&gt;
&lt;h3&gt;Rules for Streaming&lt;/h3&gt;
&lt;h4&gt;Gameplay&lt;/h4&gt;
&lt;p&gt;I don’t expect you to stream your entire playthrough. It’s perfectly fine to play privately if you want to, just please stream most of your gameplay.&lt;/p&gt;
&lt;p&gt;Only at the start do all present participants and have the stream turned on.&lt;/p&gt;
&lt;h4&gt;Title&lt;/h4&gt;
&lt;p&gt;You have a lot of freedom when it comes to stream titles.
I simply ask that you include &quot;Project Xcyting&quot; somewhere so viewers understand what it’s about.&lt;/p&gt;
&lt;h4&gt;Content&lt;/h4&gt;
&lt;p&gt;I understand that frustrating moments happen. I’m sure there will be times when you can be upset with me, too. You are absolutely welcome to express criticism as long as it stays respectful.&lt;/p&gt;
&lt;h3&gt;Rule Violations&lt;/h3&gt;
&lt;p&gt;In the end, I make the final decision on rule violations. Every case is different, but generally a rule violation will result in disqualification. If you believe someone is not following the rules, please let me know.&lt;/p&gt;
</content:encoded></item><item><title>Xcyte (English)</title><link>https://blog.catboy.best/posts/xcyting-en/</link><guid isPermaLink="true">https://blog.catboy.best/posts/xcyting-en/</guid><description>The Pokémon X/Y Project</description><pubDate>Sun, 09 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This Project is designed to be for all types of players. From players who never played the game to players who developed a deep knowledge for the game. The primary goal is to enjoy the gameplay and to experience the joy of playing the game, trade Pokémon and to battle with other players! Since the newest game (Pokémon Legends Z-A) is playing in the same region as generation 6, we&apos;re playing the original: X/Y.&lt;/p&gt;
&lt;h3&gt;How does all of this go?&lt;/h3&gt;
&lt;h4&gt;Registrations&lt;/h4&gt;
&lt;p&gt;Registrations close on &lt;strong&gt;23.01.2026 - 23:59&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Participants&lt;/h4&gt;
&lt;p&gt;Participants will be announced on &lt;strong&gt;26.01.2026&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Start&lt;/h4&gt;
&lt;p&gt;The project will officially begin on the evening of &lt;strong&gt;30.01.2026&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Tournament&lt;/h4&gt;
&lt;p&gt;The tournament will take place on the weekends between &lt;strong&gt;27.02.2026 - 29.03.2026&lt;/strong&gt;. This gives everyone 4 weeks to prepare.&lt;/p&gt;
&lt;h3&gt;What if I don&apos;t stream?&lt;/h3&gt;
&lt;p&gt;Every streamer who gets selected will receive their own team that viewers can register for to play along.
These teams will also compete in a league table at the end to earn points.&lt;/p&gt;
&lt;h3&gt;Where do I register?&lt;/h3&gt;
&lt;p&gt;Over this form: https://docs.google.com/forms/d/1rReyeOqfujPxCIsqXibnHvK54hdVzhMUfMV4rQIcLoo/edit?pli=1&lt;/p&gt;
&lt;p&gt;Additionally, you can join onto this Discord Server if you&apos;re interested: https://discord.gg/SncBqdkQ2V&lt;/p&gt;
&lt;p&gt;Choose your roles and you’re good to go!&lt;/p&gt;
&lt;h3&gt;What do I need to be able to participate?&lt;/h3&gt;
&lt;h4&gt;Emulator&lt;/h4&gt;
&lt;p&gt;We&apos;re using the &lt;strong&gt;Azahar Emulator&lt;/strong&gt;, as it is required for tools like Pokélink.&lt;/p&gt;
&lt;h4&gt;Pokélink&lt;/h4&gt;
&lt;p&gt;If you are a streamer, we need Pokélink so we can keep track of your team and progress.&lt;/p&gt;
&lt;h4&gt;The Game &amp;amp; Setup&lt;/h4&gt;
&lt;p&gt;After registrations close, we will provide help on the Discord server.&lt;/p&gt;
&lt;h3&gt;Rules when playing&lt;/h3&gt;
&lt;h4&gt;Emulator Speed&lt;/h4&gt;
&lt;p&gt;Anything between &lt;strong&gt;100-200%&lt;/strong&gt; is allowed.&lt;/p&gt;
&lt;h4&gt;Cheats&lt;/h4&gt;
&lt;p&gt;All forms of cheats are strictly forbidden.&lt;/p&gt;
&lt;h4&gt;Pokémon&lt;/h4&gt;
&lt;p&gt;In your solo gameplay, you may use any Pokémon you feel fits your playstyle or asthetic.&lt;/p&gt;
&lt;p&gt;Please use common sense when choosing names, avoid anything inappropriate.&lt;/p&gt;
&lt;h4&gt;Trading&lt;/h4&gt;
&lt;p&gt;Trading is fully allowed and encouraged between all players!&lt;/p&gt;
&lt;h4&gt;Battles&lt;/h4&gt;
&lt;p&gt;Test battles are allowed for training and to familiarize yourself with the battle rules.&lt;/p&gt;
&lt;h3&gt;Rules for Battle&lt;/h3&gt;
&lt;h4&gt;Qualification&lt;/h4&gt;
&lt;p&gt;You qualify to participate by becoming the Champion of the Pokémon region.&lt;/p&gt;
&lt;h4&gt;Format&lt;/h4&gt;
&lt;p&gt;Single Battle (1v1) with 6 Pokémon, all automatically set to Level 50. Pokémon must be unique. No duplicates of the same Pokémon species.&lt;/p&gt;
&lt;h4&gt;Mega Evolution&lt;/h4&gt;
&lt;p&gt;Mega Evolution is only allowed if both players are able to use Mega Evolution on a Pokémon.&lt;/p&gt;
&lt;h4&gt;Legendaries&lt;/h4&gt;
&lt;p&gt;Legenderies are not allowed&lt;/p&gt;
&lt;p&gt;Pseudo-Legendaries (like Garchomp or Dragonite) are allowed.&lt;/p&gt;
&lt;h4&gt;Items&lt;/h4&gt;
&lt;p&gt;While Items are allowed to be held by Pokémon, using anything in active battle (like Potions) are not allowed.&lt;/p&gt;
&lt;h4&gt;Cheat Sheets&lt;/h4&gt;
&lt;p&gt;You are allowed to keep an open type chart to check effectiveness if needed.&lt;/p&gt;
&lt;h3&gt;Rules for Streaming&lt;/h3&gt;
&lt;h4&gt;Gameplay&lt;/h4&gt;
&lt;p&gt;I don’t expect you to stream your entire playthrough. It’s perfectly fine to play privately if you want to, just please stream most of your gameplay.&lt;/p&gt;
&lt;p&gt;Only at the start do all present participants and have the stream turned on.&lt;/p&gt;
&lt;h4&gt;Title&lt;/h4&gt;
&lt;p&gt;You have a lot of freedom when it comes to stream titles.
I simply ask that you include &quot;Project Xcyting&quot; somewhere so viewers understand what it’s about.&lt;/p&gt;
&lt;h4&gt;Content&lt;/h4&gt;
&lt;p&gt;I understand that frustrating moments happen. I’m sure there will be times when you can be upset with me, too. You are absolutely welcome to express criticism as long as it stays respectful.&lt;/p&gt;
&lt;h3&gt;Rule Violations&lt;/h3&gt;
&lt;p&gt;In the end, I make the final decision on rule violations. Every case is different, but generally a rule violation will result in disqualification. If you believe someone is not following the rules, please let me know.&lt;/p&gt;
</content:encoded></item><item><title>Cutesy</title><link>https://blog.catboy.best/posts/cutesy/</link><guid isPermaLink="true">https://blog.catboy.best/posts/cutesy/</guid><description>The journey of a unified coloring logger. Useable everywhere in the same way as the other.</description><pubDate>Fri, 19 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Trigger warning: American spelling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Do you know this feeling? You have added a bunch of logging and want to make things prettier?
Pretty fast you find yourself looking add simple coloring and start seeing that it looks a little more complicated, starting to write your own little logger and keep copy pasting the same thing into your hundreds of projects thinking&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I wish i could just use this everywhere?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now if you only code in one programming language that seems like something that isn&apos;t a problem because you can just make a package for it and use it, like i did at first.&lt;/p&gt;
&lt;p&gt;Now if you were to switch from JavaScript to something like Python you&apos;d pretty quickly see that you have to rewrite your entire logic into python because the likelyhood of having the &lt;em&gt;exact same&lt;/em&gt; logger in two languages is quite unlikely. You might find similarities but at the end you&apos;ll end up with something that works differently in one language than the other.&lt;/p&gt;
&lt;p&gt;I decided to put an end because more than often i don&apos;t need complicated loggers but instead just a logger that is capabable of basic things.&lt;/p&gt;
&lt;h3&gt;Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Uncomplicated coloring with the same default color pallette&lt;/li&gt;
&lt;li&gt;Padding when using multiple loggers&lt;/li&gt;
&lt;li&gt;Write to a file when promted to do so&lt;/li&gt;
&lt;li&gt;Timestamps&lt;/li&gt;
&lt;li&gt;Naming&lt;/li&gt;
&lt;li&gt;Tracing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal? A small, simple, zero dependancy logger, that is both compatible with ANSI-8 and ANSI-256/Truecolor maintaining the same usage and functionality in every single language that the package exists for.&lt;/p&gt;
&lt;p&gt;Behold the invention made back in 2022. The original concept: &lt;strong&gt;Cutesy&lt;/strong&gt;
::github{repo=&quot;Calemy/cutesy&quot;}
:::note
Cutesy&apos;s original package is now outdated by my new standards, but will be overhauled by the changes introduced in other languages.
:::&lt;/p&gt;
&lt;p&gt;Now i had a package that made logging easy for me!&lt;/p&gt;
&lt;h3&gt;JavaScript (cutesy)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import Logger from &quot;cutesy.js&quot; //version 1.2.3
const logger = new Logger() //currently uses ANSI-256 by default

logger.blue(&quot;This part is colored blue &quot;).red(&quot;while this is red!&quot;).send()
logger.addTimestamp(&quot;hh:mm:ss&quot;).send(&quot;This text has a timestamp&quot;)
// =&amp;gt; 04:31:05 - This text has a timestamp
logger.changeTag(&quot;Debug&quot;).send(&quot;This is a debug&quot;)
// =&amp;gt; Debug | This text is a debug
logger.sendTraced(&quot;Where am I?&quot;)
//Where am I? -&amp;gt; /home/nanoo/cutesy/blog.js:9:7
logger.send(&quot;This should be saved inside a file.&quot;).save()
//Everything attatched to the message will be saved inside the file (Name, Timestamp, Trace)
logger.blurple()
//Now all messages are Blurple?!?!
logger.send(&quot;This message is Blurple&quot;)
logger.send(&quot;This one too!&quot;)
logger.green().send(&quot;Now it&apos;s green&quot;)
logger.send(&quot;Still green. surprising isn&apos;t it?&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quickly i got a reality check when i switched to Go. There is no package that does the thing i want to do in a simple manner like i&apos;m used to. So i got quickly to thinking and came up with the go-varient of cutesy. Currently called &lt;strong&gt;Goatsy&lt;/strong&gt;. It&apos;s also my first Go code that i&apos;ve published to GitHub!&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Calemy/goatsy&quot;}&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Get it? It&apos;s funny because it&apos;s &lt;strong&gt;Go&lt;/strong&gt;? &lt;strong&gt;Go&lt;/strong&gt;atsy?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Oh it just isn&apos;t funny. Right..&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Oh well now we try the same things we did in JavaScript.&lt;/p&gt;
&lt;h3&gt;Go (goatsy)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import &quot;github.com/calemy/goatsy&quot; //version 0.0.1

var logger = goatsy.New(&amp;amp;goatsy.Options{
	Truecolor:  true, //Enables truecolor, currently uses ANSI-256 by default which has to be changed.
	TimeFormat: time.DateTime,
})

logger.Blue(&quot;This part is colored blue &quot;).Red(&quot;while this is red!&quot;).Send()
logger.Rename(&quot;Debug&quot;).Send(&quot;This is a debug&quot;)
logger.Trace(&quot;Where am I?&quot;)
//Where am I? -&amp;gt; /home/nanoo/goatsy/blog.go:10

//Saving to a file is currently a WIP

logger.Blurple()
//Now all messages are Blurple?!?!
logger.Send(&quot;This message is Blurple&quot;)
logger.Send(&quot;This one too!&quot;)
logger.Green().Send(&quot;Now it&apos;s green&quot;)
logger.Send(&quot;Still green. surprising isn&apos;t it?&quot;)
logger.Color(&quot;#ff0000&quot;, 9).Send(&quot;I now used a custom color, with a fallback in case truecolor is disabled.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see. It&apos;s quite similar to each other therefore i&apos;ll still do changes to cutesy to align it with goatsy.&lt;/p&gt;
&lt;p&gt;I&apos;m now working on a Python version which i would have called qtcpy which follows a similar concept to JavaScript.&lt;/p&gt;
&lt;p&gt;My C version i would have called cuteC.&lt;/p&gt;
&lt;p&gt;Now thinking about it, i should just stick with cutesy-ext.&lt;/p&gt;
&lt;h3&gt;Language Support List&lt;/h3&gt;
&lt;h4&gt;Fully supported&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript (cutesy) - The OG 🗣🗣🗣&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Partily supported&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Go (goatsy) (soon cutesy-go)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Work in Progress&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Planned&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;C/C++&lt;/li&gt;
&lt;li&gt;Zig&lt;/li&gt;
&lt;li&gt;Rust&lt;/li&gt;
&lt;li&gt;Odin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any wishes, let me know!&lt;/p&gt;
</content:encoded></item><item><title>Amigo</title><link>https://blog.catboy.best/posts/amigo/</link><guid isPermaLink="true">https://blog.catboy.best/posts/amigo/</guid><description>It&apos;s Mino, but now in Go!</description><pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;During the time that I wrote Mino, I&apos;ve been told a lot (specially during the early days before i knew what i know now) that i should consider switching from JavaScript, due to it&apos;s limitations and non-existent typing system.
I shall now quote my favourite things that have been said to me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;JavaScript is not very performant, and it&apos;s so unsafe!&quot;&lt;/li&gt;
&lt;li&gt;&quot;If you want &lt;em&gt;real&lt;/em&gt; performance, you should use C# or Rust&quot;&lt;/li&gt;
&lt;li&gt;&quot;JavaScript is shit, you should use Python&quot;&lt;/li&gt;
&lt;li&gt;&quot;At least use TypeScript for type-safety&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The TypeScript debate was always a heated one because i had a very clear standpoint on TypeScript that i have to this day.&lt;/p&gt;
&lt;p&gt;You don&apos;t really &lt;em&gt;need&lt;/em&gt; TypeScript if you know how to write good JavaScript.&lt;/p&gt;
&lt;p&gt;The Issue i personally had with TypeScript is that it added unnecessary boilerplate to my codebase that i didn&apos;t need.
I didn&apos;t work with others and had a clear structure of what my code did. Also, using TypeScript back in 2022 with node was just annoying (honestly it still is) and i didn&apos;t see any reason for myself to go through all of the pain just to add type-safety.
I was confident enough to be able to say that i didn&apos;t need TypeScript since i&apos;ve written good JavaScript code.&lt;/p&gt;
&lt;p&gt;Someday in 2024 i started to use TypeScript more frequently in my projects but the earliest thing i&apos;ve built was Tyro by the end of 2022. An osu!api emulator fully written in TypeScript to experiment around.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Calemy/tyro&quot;}&lt;/p&gt;
&lt;p&gt;By the end of 2024 i&apos;ve fully migrated a JavaScript Project into TypeScript, Advance. The source code has not been updated by the time of writing this entry. The reason why is because it became a lot easier using TypeScript with a runtime like Bun, that supports TypeScript out of the box.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;osuAdvance/Advance&quot;}&lt;/p&gt;
&lt;p&gt;Back in june of this year i&apos;ve also rewritten Mino in TypeScript, making a few improvements but it has never been released as a stable version.
This feeling of using TypeScript more commonly in my projects gave me the idea &lt;em&gt;&lt;strong&gt;why not take it a step further and learn a new language?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Because in the end, some had a point. JavaScript does reach it&apos;s limitations when it comes to scaling, and Mino has been gathering over 1.5 million requests each month that have been handled.&lt;/p&gt;
&lt;h3&gt;How did we get here?&lt;/h3&gt;
&lt;p&gt;I&apos;ve put my hands on a few programming langauges before including Python, C# and C++. I even had my hands on Go and Rust for a little and made the most rough sketch for imitating the download route and i&apos;ve had to say, i didn&apos;t really enjoy it that much. It felt overly complex and kind of hard to get into, so i dropped the idea and left it for a while before deciding to try it again in July with the most promising looking language, &lt;strong&gt;Go&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I decided to take another proper look into the language and did a lot of trial and error. A solid week later i had the first version that i started to understand how things work in Go and started to experiment even more and got down the basics like structs, error handling and modules.&lt;/p&gt;
&lt;p&gt;Over the entire month of July, i&apos;ve started to actually enjoy re-coding this project into Go but of course i faced some challenges because things obviously work different than in JavaScript.&lt;/p&gt;
&lt;p&gt;:::note
For the future of this post i&apos;ll be just using TypeScript code in my examples.
:::&lt;/p&gt;
&lt;h3&gt;The things i&apos;ve noticed&lt;/h3&gt;
&lt;p&gt;Getting into Go was interesting because of the way how everything was handled.&lt;/p&gt;
&lt;h4&gt;Web Requests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;You didn&apos;t have a native json function for web requests like you have in JavaScript.&lt;/li&gt;
&lt;li&gt;You actually have to handle things like closing the web body in order to not leak memory, which also extends to other systems like files.&lt;/li&gt;
&lt;li&gt;Making a simple web request usually ends up a little more boilerplate other than your typical fetch function in JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;try {
    const response = await fetch(`https://catboy.best/api`)
    const data = await response.json() as any
} catch (err) {
    throw err
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;quickly became&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;req, err := http.NewRequest(&quot;GET&quot;, &quot;https://catboy.best/api&quot;, nil)
if err != nil {
	panic(err)
}

resp, err := (&amp;amp;http.Client{}).Do(req)
if err != nil {
	panic(err)
}

defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
	panic(err)
}

var data map[string]interface{}

if err := json.Unmarshal(body, &amp;amp;data); err != nil {
    panic(err)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the worst part is that parsing json in Go is another huge pain in the ass if you want to parse it into structs.&lt;/p&gt;
&lt;p&gt;For those who are unaware structs are build like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type User struct {
    ID int
    Username string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to parse json into a struct you have to define json fields on the struct.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type User struct {
    ID int `json:&quot;id&quot;`
    Username string `json:&quot;username&quot;`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if you were now to unmarshal json into the struct it would look like this&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var user User

if err := json.Unmarshal(body, &amp;amp;user); err != nil {
    panic(err)
}

//Now you can access things like user.ID and user.Username
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you had any extra fields, you just wouldn&apos;t have them anywhere unlike in JavaScript. (Which honestly can be fine for most cases)&lt;/p&gt;
&lt;p&gt;It does become a problem however, if you expect to have access to all dynamic fields at all times since you have to just know what payload you receive. With that in mind i made the basics and things seemed fine™ so i didn&apos;t care too much.&lt;/p&gt;
&lt;h4&gt;Multithreading&lt;/h4&gt;
&lt;p&gt;God i cannot describe how much i love goroutines. Just throw a &quot;go&quot; before a function and it runs on a seperate thread. How awesome is that?
JavaScript could never be that smooth. Nodejs did introduce worker threads for a while but eh, it&apos;s just not the same and harder to manage. Speaking of harder to manage!&lt;/p&gt;
&lt;h4&gt;Promises (async)&lt;/h4&gt;
&lt;p&gt;JavaScript really spoiled me with promises, although Golang does not really need the same principle since goroutines make multithreading more available and if you want to wait for all the goroutines to finish, you just add a WaitGroup, call wg.Wait() and that&apos;s it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function networkTask(): Promise&amp;lt;number&amp;gt; {
    await Bun.sleep(1000)
    return 1
}

async function ioTask(): Promise&amp;lt;number&amp;gt; {
    await Bun.sleep(2000)
    return 1
}

//Instead of calling:

await networkTask() //takes 1 second
await ioTask() //takes 2 seconds
//Total wait time: 3 seconds

//you instead use:

await Promise.all([
    networkTask(),
    ioTask()
])
//for a total wait time of 2 seconds since we wait for the slowest to finish loading in parallel.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in Go the same principle looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var wg sync.WaitGroup

func main(){
    //instead of:
    networkTask()
    ioTask()

    //use:
    wg.Add(2)
    go func(){
        defer wg.Done()
        networkTask()
    }

    go func(){
        defer wg.Done()
        ioTask()
    }

    wg.Wait()
}

func networkTask() int {
    time.Sleep(time.Second)
    return 1
}

func ioTask() int {
    time.Sleep(time.Second * 2)
    return 1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Works perfectly fine and isn&apos;t much different from javascript while doing &quot;true&quot; multithreading.&lt;/p&gt;
&lt;p&gt;Yes i know there are channels for promises, but eh i don&apos;t want to get into that here.&lt;/p&gt;
&lt;p&gt;I was very fascinated by the way how ratelimiting worked on multithreading, that i even made a JavaScript module to make it easier there too.
::github{repo=&quot;Calemy/ticking&quot;}&lt;/p&gt;
&lt;h3&gt;The works&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Anyways&lt;/em&gt;, i worked on this Go version a lot and even worked on it during Cavoe&apos;s osu! Event 2025 in August with feedback of a few friends of mine.
Shoutout to Marti (you absolute 👑) for letting me use his laptop to actively code on it since i left mine at home.&lt;/p&gt;
&lt;p&gt;I managed to cut loading times during routes like audio preview or novideo files, improving them up to a whopping &lt;strong&gt;50x performance increase&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To put some perspective; serving the .osz of the Unforgiving without video took:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;about 5 seconds&lt;/strong&gt; on Mino Version 4&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2.5 seconds&lt;/strong&gt; with multithreading on the unreleased Mino Version 5&lt;/li&gt;
&lt;li&gt;while it got reduced to only &lt;strong&gt;150ms&lt;/strong&gt; in Go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;you can see similar improvements for audio preview and raw audio serving, which makes it a huge success.&lt;/p&gt;
&lt;p&gt;After a lot of testing around with the database, i&apos;ve now decided to take a hybrid approach; Filling meilisearch with only necessary data that is relevant for searching, while storing the full data now in sqlite. Yes, you&apos;ve heard this correctly. I&apos;m using sqlite for a high scale application because Mino actually reads most of the time when it&apos;s not actively crawling from 0, which makes sqlite a perfect fit since it&apos;s lightweight, doesn&apos;t not need to be installed as an extra dependency and is also blazing fast, having a very low response time.&lt;/p&gt;
&lt;p&gt;This also made me rethink my approach on my structs because if you ever looked at osu&apos;s api v2, it gets messy really quick. Instead of treating every field in a column i just dynamically store the json as it&apos;s own data field. This way it stays dynamically updated at all times so i always stay compliant with the newest api v2 spec. It also means i don&apos;t need to parse the entire json anymore for each entry, which also saves a little time.&lt;/p&gt;
&lt;p&gt;Now if you&apos;ve read the first post of mine, you might ask me: &lt;em&gt;But Nanoo, what about Cheesegull?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes, i thought about that, but since i don&apos;t even need most of the fields. Using go&apos;s native unmarshal would be wasteful, because it goes through the entire json. Instead i use gjson and only select the fields i need. (which in my case is about 10 fields out of like 25 or so) and save myself a lot of memory, since i hold less bytes and cpu time.&lt;/p&gt;
&lt;p&gt;So far that has been my Journey with Amigo, and i&apos;ll keep you updated.&lt;/p&gt;
</content:encoded></item><item><title>Beemo</title><link>https://blog.catboy.best/posts/beemo/</link><guid isPermaLink="true">https://blog.catboy.best/posts/beemo/</guid><description>A journey of making an osu!lazer server written in javascript.</description><pubDate>Mon, 01 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is where it all began&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Calemy/beemo&quot;}&lt;/p&gt;
</content:encoded></item><item><title>Mino</title><link>https://blog.catboy.best/posts/mino/</link><guid isPermaLink="true">https://blog.catboy.best/posts/mino/</guid><description>The JavaScript Beatmap Mirror</description><pubDate>Sat, 12 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My biggest project to this day is Mino. A from scratch written JavaScript Beatmap Mirror that has everything someone could ask for.
It even became the name for a company i&apos;m a part of!&lt;/p&gt;
&lt;p&gt;But how did i even get the idea?&lt;/p&gt;
&lt;p&gt;Well, simply said: i was tired that everyone else sucked.&lt;/p&gt;
&lt;p&gt;You had mirrors like Chimu, Beatconnect or Kitsu that all came with major drawbacks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chimu was in maintenance&lt;/li&gt;
&lt;li&gt;Beatconnect was horrendously slow and had no public api&lt;/li&gt;
&lt;li&gt;Kitsu was new and unreliable to stay running&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One day i was annoyed and thought: &lt;em&gt;what the hell, why not just make my own? How hard can it be?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So i made some sketching for what i&apos;d need to do.&lt;/p&gt;
&lt;h3&gt;Step 1 - The database&lt;/h3&gt;
&lt;p&gt;I was lucky to be so far involved with Kitsu, that i had access to the structure they used.
I followed the structure and therefore landed on using mysql as my database to store the metadata.&lt;/p&gt;
&lt;h3&gt;Step 2 - The API&lt;/h3&gt;
&lt;h4&gt;Step 2.1 Metadata&lt;/h4&gt;
&lt;p&gt;Getting the metadata via crawling was the next step so i can populate the database.
It was relatively easy back then using the osu! api v1 by using an api key.
It did limit me to 60 requests/min though.&lt;/p&gt;
&lt;h4&gt;Step 2.2 Beatmaps (.osz files)&lt;/h4&gt;
&lt;p&gt;Now the tricky part was getting the actual .osz files to store and serve when requested.
After a lot of digging, i found out that the osu! api v2 does in fact have an endpoint for downloads!
&lt;em&gt;check notes&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;oh wait it&apos;s locked behind a client scope... &lt;em&gt;sigh&lt;/em&gt; great.&lt;/p&gt;
&lt;p&gt;After some more digging i got the necessary resources to emulate the lazer client
&lt;em&gt;which i won&apos;t disclose exactly how&lt;/em&gt;
and got the necessary scope to make the request.&lt;/p&gt;
&lt;h4&gt;Step 2.3 Beatmaps (.osu files)&lt;/h4&gt;
&lt;p&gt;This was fairly easy because .osu files are served via a different api that is public.
Requesting https://osu.ppy.sh/osu/:id would give me the .osu file for the difficulty which is all i needed.&lt;/p&gt;
&lt;h3&gt;Step 3 - Implementation&lt;/h3&gt;
&lt;p&gt;Now i got everything i needed to have the most basic mirror that has metadata and files that are cached once requested.
I did a very quick implementation and tested it out on my own osu! server &lt;a href=&quot;https://blog.catboy.best/posts/horizon&quot;&gt;Horizon&lt;/a&gt;
since that was the initial trigger of why i got mad in the first place.&lt;/p&gt;
&lt;p&gt;Things looked fine and things loaded slow at the beginning and when cached immediately loaded, which at the time, was a win in my book.&lt;/p&gt;
&lt;p&gt;I then wanted to figure out how to do beatmap searching inside the client so that&apos;s what i worked on next.&lt;/p&gt;
&lt;p&gt;After some request catching inside the server&apos;s console i made a quick mockup inside my own API doing your typical full text search shenanigans.
Once finished, i did some testing and it worked great! I got the songs i was looking for and the filters were working fine.&lt;/p&gt;
&lt;p&gt;I got so excited about how &quot;fast&quot; things were running, that i recorded a video and asked RealistikDash (a virtual collegue of mine) to check it out.&lt;/p&gt;
&lt;p&gt;He got back to me soon after, and asked me if he could test it on his own server aswell.
I told him that i don&apos;t have a public endpoint yet, since it was in development and not &lt;em&gt;made&lt;/em&gt; for usage outside of my server but that i&apos;ll get on it.
So i took a random domain i still had laying around; &lt;a href=&quot;https://catboy.best&quot;&gt;catboy.best&lt;/a&gt; and slapped my service onto it naming it Mino.&lt;/p&gt;
&lt;p&gt;Of course having a quick laughter about it, he also informed me that the search did not work for him and we went investigating.
And there it hit us, Cheesegull.&lt;/p&gt;
&lt;p&gt;:::note[Cheesegull]&lt;/p&gt;
&lt;p&gt;Ripple&apos;s formatting for beatmaps used in &lt;em&gt;most&lt;/em&gt; osu! private server instances made back in 2016
:::&lt;/p&gt;
&lt;h3&gt;Step 4 - Cheesegull&lt;/h3&gt;
&lt;p&gt;To satisfy the standard for Cheesegull i did some rewriting of the API and let me tell you, Cheesegull definetly had it&apos;s deserved place!
But now it&apos;s just a pain in the ass since api v2 exists and literally everyone still adopts Cheesegull as the standard in their server
&lt;em&gt;(what&apos;s up with that anyways?)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After doing those changes i got back to my RealistikDash and he gave me the green light that everything worked as expected.
He also suggested to make it a public thing since it went &lt;em&gt;really&lt;/em&gt; fast and people could use it considering the asfore above mentioned and i thought &lt;em&gt;sure what&apos;s the worst that could happen?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, the &quot;worst&quot; that happened is that it actually gained attraction from other server owners and developers.
And of course when something is booming in the backend the first question asked by a user is &quot;when frontend?&quot;&lt;/p&gt;
&lt;h3&gt;Step 5 - Frontend&lt;/h3&gt;
&lt;p&gt;I&apos;m not a frontend genius, by any means. I used some bootstrap and wrote some silly little thing in like 2 days worth of time that featured:&lt;/p&gt;
&lt;h4&gt;Homepage&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;A landing page where you can see the crawler&apos;s progress and what data has been recently added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Search&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;A search page to search for beatmaps! (wow)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;About&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;A quick overview of what this project actually is, who contributed to it and a discord server to join.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course not forgetting about an E-Mail for DMCA complains. (still haven&apos;t received one now that i think about it)&lt;/p&gt;
&lt;p&gt;Time flies and all of a sudden in the span of a month, most people have switched to my mirror.
&lt;em&gt;Well great now i&apos;m stuck with the domain catboy.best for this because i didn&apos;t think this would actually take off.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the meantime i made a switch from my database going from mysql to meilisearch. A search database designed for specifically that and have not switched off from since and also marked Version 2. (besides this weird mongo phase i had for a month but psscht we don&apos;t talk about it here)&lt;/p&gt;
&lt;h3&gt;Fixes &amp;amp; Optimizations&lt;/h3&gt;
&lt;p&gt;Of course, with the growing amount of users, there were bugs bound to be discovered and optimizations to be made for a more stable Mino.
It&apos;s not some small 4 fun project anymore but instead developers decided to actually use it as a dependancy so i had to use the advantage.
Another month passes by, Chimu gets out of maintenance.
Once a giant lost 50% of it&apos;s users, Kitsu rebrands and rewrites their backend but lost 80% of their users due to prior complications.
All of those users got to me, but now it&apos;s more intense because Mino has to perform well to stay on top.
I also got some concerning amount of negativity back from a certain developer that shall not be named who wasn&apos;t happy with my mirror&apos;s existence.&lt;/p&gt;
&lt;h3&gt;Quick Rundown of what else happened&lt;/h3&gt;
&lt;p&gt;Since the project is 3 years old at the time of the writing (September 19th, 2025), i&apos;ll spare you the boring details (since i can&apos;t remember most of them anyways)&lt;/p&gt;
&lt;h4&gt;Webosu - May 2022&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Mino became the main mirror for the web ported version of osu! &lt;a href=&quot;https://webosu.online&quot;&gt;webosu!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;bancho.py - June 2022&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Mino also became the standard in cmyui&apos;s &lt;a href=&quot;https://github.com/osuAkatsuki/bancho.py&quot;&gt;bancho.py&lt;/a&gt; (formerly gulag) repository.
Go check it out if you&apos;re interested in making an osu server for yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;::github{repo=&quot;osuAkatsuki/bancho.py&quot;}&lt;/p&gt;
&lt;h4&gt;Team-Up with Philsty - July 2022&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Since 2022 i&apos;ve been working closely with Phil.
He was so kind and provided a big part of Mino&apos;s infrastructure and taught me to think about things that i haven&apos;t paid much attention to before.
He also works with me on Advance!&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Geolocation - October 2022&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;We setup multiple server (one in the US and one in Europe) and gave it automatic geolocation so each user has the smoothest experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CI/CD - April 2023&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;With the work of Phil, pushing changes to servers (yes, at that point it was servers) was automated and worked like a charm.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Version 3 - September 2023&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Mino officially rolled out Version 3 with the new versioning system (i&apos;ve done a billion rewrites and called them by major versions before)&lt;/li&gt;
&lt;li&gt;Therefore i landed from Version 7 to Version 3.3.6&lt;/li&gt;
&lt;li&gt;Major bug fixes that affected stability and performance&lt;/li&gt;
&lt;li&gt;Introduced the fastest latency making it the top contender since&lt;/li&gt;
&lt;li&gt;Huge consistency upgrades&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Version 4 - March 2024&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Mino officially rolled out Version 4 making great changes to internal structure.&lt;/li&gt;
&lt;li&gt;Database optimizations&lt;/li&gt;
&lt;li&gt;Performance improvements on certain routes&lt;/li&gt;
&lt;li&gt;Minor Bug fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Frontend Rewrite - July 2024&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Refining my frontend skills, i decided to give it another go&lt;/li&gt;
&lt;li&gt;No bootstrap, but tailwind&lt;/li&gt;
&lt;li&gt;Cleaner and more modern UI&lt;/li&gt;
&lt;li&gt;It&apos;s still bad, but at least it looks nicer and displays the pure backend performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Version 5 (The TypeScript update) - June 2025&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Rewritten Mino in TypeScript using Bun&lt;/li&gt;
&lt;li&gt;Increasing performance on bucket requests&lt;/li&gt;
&lt;li&gt;Increasing general performance across all routes using Bun&apos;s http module&lt;/li&gt;
&lt;li&gt;Pain and suffering figuring out Bun&apos;s http module and Zig&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;The Future - Pending&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Since this is fairly recent, you&apos;ll be able to know about it on another blog post. Stay tuned!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Last Words&lt;/h3&gt;
&lt;p&gt;Thanks for listening to this yap fest of a blog post. This is my very first, so i hope you were able to not only endure but also enjoy it as much as i did writing this.&lt;/p&gt;
&lt;h3&gt;Special Thanks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;RealistikDash&lt;/li&gt;
&lt;li&gt;Philsty&lt;/li&gt;
&lt;li&gt;cmyui&lt;/li&gt;
&lt;li&gt;lenforiee&lt;/li&gt;
&lt;li&gt;tsunyoku&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>