2025 in review

23 minutes
Reflection Year in review
Table of Contents

Last year, I wrote 2024 in review. There are many good things about that post. I reviewed it a few times throughout the year, curious about the changes in my mental state since then and about the goals I had set. It has also been fun to share it with my friends and acquaintances. And, most importantly, it presented a good opportunity for reflection at the time of writing. So, here I am, writing a follow-up :)

2025 has been a transformative year. It had its ups and downs and felt somewhat chaotic. But the overall feelings about it are positive, and I think I made a lot of progress.

Reintroduction 🏳️‍⚧️

Greetings! Let me rei-introduce myself. My name is Rei, and my pronouns are she/they.

Для русскоговорящих (For Russian speakers)

Меня зовут Рей (произносится «Рэй»). Я использую местоимения она/они.

My feminine appearance entered the public beta in summer 2024, and my transition reached a pre-release state in summer 2025. Today is the release day 😸

I had been thinking about whether transitioning was something I wanted for years before that, and I am glad I had finally gotten around to it. Making up my mind was hard; I was never fully sure, and it was getting exhausting. However, by mid-2025, I understood that I was not really bothered by any possible consequences.

And I thought to myself
fuck it we ball.

This decision has made me much, much happier. I am appreciating literally every change and rei-discovering so many things! 10/10, would do it again.

Key events of 2025

At the time of writing, I am still processing just how many things happened in 2025. A few things deserve more than just a line in a list, so I gave them separate sections. There is a Table of Contents at the top of the page if you need it :)

Event highlight: Factorio LAN party

For my birthday, my friends and I organised a Factorio LAN party that went on for three days. More than 10 people played the game, and at the peak, there were eight simultaneous players.

We put a lot of effort into the event. To make sure things went smoothly, we planned when people were going to come and leave, and whether they’d like to sleep over. That allowed us to make sure there was sufficient space and food for the guests. We also set up a wired network connection for everybody who wanted to use it.

For the game, we set some rough goals, but in general, just tried to make sure that people were not feeling lost. We were playing with the Space Age DLC, and we got to space by the end of day three.

To make the game more fun, we wrote a mod for Factorio to export game stats to Prometheus. It is based on graftorio2 but has some unique statistics and bugs. One of the unique statistics is «Area Paved» — we all know it’s not a megabase if there is no concrete. During the game, we projected a Grafana dashboard with game stats onto the wall, and one of the guests even wrote custom CSS to give it party vibes.

I recorded a time-lapse of the game, if you’d like to see it:

Factorio Grafana projected onto a wall in my living room

Factorio Grafana projected onto a wall in my living room

Event highlight: Moving

At the start of the year, I moved into a different flat, having spent three years in the last one. I really appreciate the move, as I find the new area much more enjoyable. A few months after I moved, I drew a floorplan of the new place.

Now, almost a year later, this place feels like home even more than the last place did after three years there. I put a lot of effort into adapting to the new place and into adapting it for me. The scope of these adjustments can grow pretty big, so I mostly focused on the following:

UV-reactive stars on the ceiling, lit up by UV fairy lights

UV-reactive stars on the ceiling, lit up by UV fairy lights

This year, I learned a lot about optimising my living and working space. At the same time, there are a couple of things that are becoming increasingly clear to me.

First, for many reasons, I need more space. I do a lot of things at home, so the space has to stay highly multifunctional, and that often causes conflicts between activities. This is complicated by the fact that a lot of the furniture is «glued» in place, as there is no better place for it. And, well, I also just want to have a guest bedroom, a guest desk, and a greater ability to reconfigure my flat.

And the other thing — I want to have more control over the noise levels in the flat. The biggest noise sources are the boiler, the radiators, and the fridge. Don’t get me wrong, on their own they are alright, but any source of noise can drive you mad if it’s around you all day, every day.

There are many other little things that contribute to the soundscape. Just for instance — squeaky floors (don’t get me started on how uneven they are!), coil whine from various power supplies and tech devices, fan noise, upstairs neighbours walking around or doing laundry. My bed is also right against the wall of the stairwell, so all of the corridor sounds get nicely amplified for the optimal sleep experience.

So, having learned so much, maybe I will move again in 2026 :)

Project highlight: Donut renderer

In the summer, I decided to develop a video game a rendering engine. I used Rust and wgpu.rs to make something inspired by Towerfall. Apart from wanting to use said tools, I had more goals in mind:

I don’t feel like I got that project to a conclusion, but I am very happy with what I’ve done and what I’ve learned. The project is called donut because, like Towerfall, it is topologically equivalent to a torus 1.

One of my favourite parts of the project is an implementation of an algorithm for calculating Visibility Polygons. I spent a long time writing a post about it, but the post is still a draft at the time of publishing.

I also had fun fiddling with the geometry to implement simple impulse-based physics for 2D bodies. I am looking forward to learning more about Collision response in the future.

I really enjoyed writing the rendering part of the engine. Learning resources on wgpu were able to answer my questions, and (to my surprise) I had a lot of fun reading through the WebGPU Reference and the WebGPU Shading Language (WGSL) Reference in my spare time. A lot of knowledge from my past experiments with OpenGL and Vulkan translated to WebGPU quite well, too.

More about the approach to rendering

The current renderer utilises an approach called Deferred Shading. I really enjoyed stumbling upon it by myself once I understood what I could do with the information generated by the Visibility Polygon algorithm. Rendering happens in three passes, where:

A bunch of videos from different stages in development

Project highlight: Cryptodancer keyboard

At the start of the year, I felt like I wanted to improve the user experience in my interactions with digital devices. Since I was also interested in learning how to design PCBs and wanted to manufacture a PCB without using chemicals, I decided to make another custom keyboard. I called it Cryptodancer, inspired by the title of the game «Crypt of the NecroDancer» (there is no connection).

The keyboard lit up by a UV lamp

The keyboard lit up by a UV lamp

I started by deciding which components I was going to use and designing the PCB in KiCad. I also needed to decide how I was going to manufacture it, and I decided to mill it on the CNC router that I used when working on my last keyboard at the Edinburgh Hacklab.

Once I had the design, I tried to use several Computer-aided manufacturing (CAM) tools to generate G-code for the CNC router. Last year, I used Autodesk Fusion for that, but these days I am more allergic to Windows and to cloud-oriented software. For some reason, I could not get any of the CAM tools I tried to work on Linux, so naturally, I decided to implement G-code generation myself: ftvkyo/svg2gcode on GitHub.

More about the G-code generator

My initial idea for the G-code generator involved implementing an entire library for doing Boolean operations on polygons — I could not let down the brain worm that got into me at the end of 2024. After some time, I understood that I did not have the time to implement all the hard algorithms, so I turned to using the geo ecosystem. This is what the generator does:

  1. Read the job config, including:
    • SVG file to use
    • Operation type: engrave, cut, drill, or bore
    • Milling bit size and shape
    • Filters, such as minimal and maximal circle radii for the drilling and boring operations
  2. Read the input SVG and extract all the circles and straight lines (and straight path segments) that match the job filter. Yes, everything else is ignored.
  3. Expand the stroke of the straight segments, giving them thickness and turning them into polygons. Also turn circles into polygons.
    • If cutting or engraving contours, expand (dilate) all polygons by a value based on the milling bit size and shape
  4. Walk all segments and issue movement commands to an encoder that checks the validity of issued moves (e.g. disallowing rapid movements when the milling bit is engaged)
  5. Export the resulting G-code from the encoder

After I had the G-code, I was able to mill the PCB as planned. In total, I made three PCBs, iterating on some traces and milling settings. The milling was single-sided, so I had to solder a lot of bridges made out of diode legs 🙈

Traces on the third PCB

Traces on the third PCB

The keyboard itself is column-staggered, with the microcontroller sitting between two angled halves. The halves are 30 keys each, in 6×5 matrices, with each half also having a linear encoder in the thumb cluster.

I implemented a cursed custom encoder behaviour in QMK. I made the encoders pretend to be arrow keys or the mouse (like an Etch A Sketch!), depending on the mode. Moreover, I added an acceleration feature to them: if they register that they are being turned faster than some threshold, they send multiple arrow key or mouse movement commands per tick. I had a lot of fun combining that with noise from a piezo buzzer; it improved the experience of using the encoders.

I am happy with the project — I learned a lot and got to write some interesting code. And even though the keyboard currently does not work, it has made a big and positive impact on my life this year.

For example, it pushed me to finally move to Colemak Mod-DH (ortho version), which I use full-time now. Even though I currently only type at 70 WPM, I really enjoy the experience, so I will keep using it (and get faster). Using QWERTY, or even just row-staggered keyboards, has become more of a pain now, though.

The keyboard has also led to me connecting with some awesome people, so that’s also cool about it :)

Project highlight: 5.1 audio system

In April 2025, through a friend from the lab, I acquired a central unit / amplifier from a Logitech® Z906 surround sound system.

The stock composition of Logitech® Z906

I wanted to use that amplifier, but it could not be controlled without a console, which I did not have. What I had was a PCB produced by that same friend that allowed me to connect an ESP32-S3 to the console port of the central unit. The friend also provided some other resources:

Based on those, I wrote my own firmware for the ESP32-S3: ftvkyo/ggroohauga-rs on GitHub. I used Rust with esp-idf-hal and implemented the following features:

Example output from ggroohauga-rs over MQTT

Example output from ggroohauga-rs over MQTT

Somewhere in-between, I acquired and connected the other speakers, completing the MVP. There are still some hardware things to improve, and a lot of software stuff to work out. I am looking forward to future improvements in the user experience of this system.

About the audio pipeline

One of the software things to work on is supporting switching between playing 2-channel and 6-channel audio. The speaker is connected to my PC over three AUX cables (each carrying two channels), and it has a bunch of channel mapping modes:

In an ideal world, you would use «None» for playing audio mastered for six channels, and «3D» for creating a «surround» effect for the more common 2-channel content. Unfortunately, it turns out that the «3D» mode has a big issue. Specifically, certain bass-heavy or distortion-heavy tracks make the rear speakers crackle, sound corrupted, or compressed. I enjoyed the surround experience otherwise, so I figured out how to upmix 2-channel audio into six channels in software on my PC.

To do the upmixing, I used CamillaDSP, which another lab friend had recommended. First, I created a virtual 2-channel PulseAudio Sink using PipeWire, and then made CamillaDSP listen to that sink, process the sound, and output it into the 6-channel ALSA device. I uploaded my config as a GitHub gist.

Unfortunately, as I understand it, outputting through ALSA rather than PulseAudio means that other applications cannot output to that device at the same time. I would use PulseAudio, but for some reason the overwhelming majority of my attempts generated chopped-up sound, sometimes just silence, and it could get fixed and broken again by simple program restarts, with no configuration changes.

Other events and projects

I organised an «OpenSCAD for Beginners» workshop at Edinburgh Hacklab. You can find the slides on GitHub: ftvkyo/openscad-workshop. A few of my colleagues came to Edinburgh for the workshop, and I was very happy to see them.

I did a lot of 3D-designing and 3D-printing and levelled up my OpenSCAD incantations (with a particular focus on curves). The culmination of my OpenSCAD journey of 2025 is a set of Cherry MX-compatible keycaps. Their shell is generated by interpolating between differently positioned squircles. Most offsets and sizes are configurable, and interpolation is controlled by an assortment of easing functions.

I printed the keycaps out of PLA on my Ender 3V3 SE with a 0.25 mm nozzle and 0.075 mm layer height. The source is here: keycaps/mx_v4.scad in ftvkyo/openscad on GitHub.

Keycaps in question.

Keycaps in question.

I also did a bunch of things with my IKEA Ivar shelves. My friend and I painted one double unit, and I used the other double unit to make a giraffe a projector stand, a steering wheel rig, and a few other small things.

I went to 20 parkruns and organised a bunch of boardgame, video game, and movie-watching events. I did a bunch of drawing, some leatherwork, and many more various little things!

Travel and holidays

My friends and I rented a narrowboat and travelled on it from Falkirk to Winchburgh Marina and back over four days. That was a very fun adventure that included going through the Falkirk Wheel twice, finding a sheep skull, exploring multiple towns, rescuing a drowned drone, and even ordering a taxi by calling their dispatch centre!

View from the narrowboat

View from the narrowboat

I went to London twice, for a total of 13 days. I saw Yoasobi at Wembley Arena, went to the Thames Traditional Boat Festival in Henley-on-Thames, and rode on the (miniature) Great Cockcrow Railway.

At the Great Cockcrow Railway

At the Great Cockcrow Railway

The second trip to London was also the first time I travelled truly by myself. I stayed in a hostel and did a lot of walking, coding, and writing in between hanging out with friends.

I saw my childhood friend in Sheffield before she left the country. I explored Liverpool and went to a Pendulum set there.

Work stuff

Work life has also been eventful. I went on two work trips over ten days in total, both for productivity and social purposes. I got to meet most of my colleagues in person; it was wonderful, and I am looking forward to future gatherings.

Our product, SCALE, received a lot of updates and went from v1.2.0 to v1.5.0. I wrote a post about using SCALE to build and run GOMC. The company, Spectral Compute, raised $6 million, appeared at multiple conferences, and even got featured in Business Insider!

I am proud to be a part of it all!

Reflection

Just like last year, this post is a good opportunity for reflection. In the last post, I openly wrote about ADHD, depression, burnout, and anxiety. First, I will give an update on how that’s going, and then I’ll look into a few other things.

Anxiety sucks!

CONTENT WARNING: Self-doubt.

Can you guess what thoughts I’ve experienced while writing this year’s post?! Let me try to summarise:

Thankfully, regardless of how true those are, I have plenty of counterarguments that make this all worthwhile:

I am also writing this post in spite of being anxious. Yes, it is scary to talk about mental health. It is scary to talk about my transition. But I do not think it should be scary. I do not want to let these fears linger, so that’s why I do it! Paradoxically, showing my vulnerability makes me feel safer.

I am making progress

To my surprise, I feel like my depression has improved, even though I have not been diligent with antidepressants. I think it is the consequence of my life changing drastically due to being a part of Edinburgh Hacklab, interacting with lots of wonderful people, and doing so many cool things throughout the year.

My burnout does not have that «hopelessness» flavour to it anymore, although I still feel demotivated about many things. Most of the time, I still feel like there is too much that demands my attention. Juggling work, hobbies, relationships with people, adequate rest, life admin, touching grass, food intake, self-care, laundry, cleaning, sleep—it is a lot.

However, I feel like I have been making a lot of progress. I got quite a bit better at juggling the needs and the joys, but there is still room for improving my «organised chaos». I also think that the amount of stuff I have done in 2025 is a bit scary. Almost as if I have been speedrunning being happy 😅

At the moment, I feel like anxiety is the number one contributor to my life challenges. The symptoms of Generalised Anxiety Disorder (GAD) seem to be quite relevant. So, at the moment, I am working in that direction.

A few other things that I want to work on are:

Rei-connection

CONTENT WARNING: Emotions, childhood trauma.

There is a song by Madilyn Mei called «What’s Going On?!» that captures my current vibe quite well. The full lyrics are available on Genius, but here is how it starts:

I am an alien
My rocketship is human bone and skin
I’m something smaller
Staring out the skull
With a panel of wire
And buttons I don’t understand
Spamming every one of them
So does being human mean
Pretending to know what’s going on?

I have lived in many different environments — first, nine years in six different schools, two years in a vocational school, two years in and around university, then I left Russia and spent two years between the Philippines and Hong Kong, and finally, four years in Edinburgh. Naturally, I have been exposed to many different life situations from different sides.

That experience ended up being a double-edged sword for me. It helped me navigate my life and sometimes allowed me to give spot-on advice to others. But it combined poorly with some difficulties I had with handling my emotions that I carried over from my childhood.

Back in my childhood, I was somewhat of a menace. People seemed to really like some parts of me, and really dislike some other parts. Unfortunately, I did not have fine-grained control over that, nor an understanding of what was wrong with me. So, at some point, I started suppressing my emotions in favour of intellectualization.

I learned to justify the behaviour of others instead of getting angry at them. I do not know when was the last time I was genuinely angry at somebody. Where most people get angry, I usually think, «I understand how it happened, I understand how you got there,» and simply feel sad that life has gone this way. It’s as if I just do not see the point, as if the anger feels counter-productive as a whole.

I learned not to cry. Crying in front of other people felt like I was affecting their judgement. I concluded that such behaviour must be equal to emotional manipulation, and that was not something I wanted to do. There were also some conflicts in which crying worked as a «reset» point that would calm things down for the time being, only for them to come up again later.

Crying by myself felt counter-productive too. I cried a bunch while I was stuck alone in a hotel room in the Philippines for half a year during COVID-19, and I burned out on that because I felt like there was nothing I could do.

The detachment from emotions also creates a multitude of more subtle issues. For instance, I struggle to understand how I feel about various things. I find it quite frustrating.

There is probably more to this all, but I think I captured the overall state of my being quite well. The bad news is that this affects me and people around me to this day. The good news is that I seem to be aware of this, as aware as ever, and I am working on reconnecting with my emotions.

I have been somewhat aware of these issues for a long time now, but just like my anxiety issues, they became much more apparent once I acquired close friends again. Thankfully, my outlook on this is very positive:

Goals

At the end of 2024, I set a bunch of goals for 2025. I did not get them all to 100% completion, but I think that’s fine. I am quite happy with how 2025 turned out, so I won’t go over those goals individually.

In 2026, my «functional» goals are:

Some of my «fun» goals for 2026 are:

Thank you

Just like last year, people are one of the things that made 2025 so great. I want to thank all the people who provided support, advice, listened to me, and simply existed.

Thank you, Mom, Alla, and Oleg.

Thank you Ariadne, Artem, Ashley, Blake, Callen, Chris, Cicely & Colin, Dan F, Dylan, Emily K, Eugene & Maria, François, Giulio, Gregor, Ilya & Maria, Ivan, Jared, Jon, Julia, Justine, Lamis, Mary & Max, Matthew, Matt & Mel, Michael, Miron, Natalia K, Nicholas, Nina, River, Rocket, Ross, Sam, Sapphire, Sean, Simon, Solomon, Sophia, Taylor, Vanessa, Vera, Yara, Yasha.

Thank you, fellow Spectral Compute colleagues and Edinburgh Hacklab members.

You made my year. Best wishes for 2026!


  1. Wikipedia: Wraparound ↩︎