Every now and then, I share bits and pieces on my social media accounts about the work I’ve been doing on MiniSwift, MiniKotlin, and MiniSharp, as well as my multi-platform solutions with Kavak, the umbrella platform above them. Naturally, though, that can get a little confusing.
So I’ll try to explain things in a more organized way: what I’ve solved and what I may be able to solve.
If we had to name the biggest problem in computer history, we could probably call it the portability problem. If I remember correctly, before Zuse’s Z1 in the 1930s, a written program had to be compiled again from scratch every single time someone wanted to run it.
After that, these problems were solved one by one, and that’s how we made it to today. I remember Java’s slogans from when it first came out—back when its name was Oak ;-).
We’ve developed such a language that your refrigerator and your coffee machine will be able to talk to each other.
Hmm, an interesting claim. But that claim was really just a slightly dressed-up advertising version of the motto that a program could run on every platform without any trouble. (They meant the devices would communicate through XML.)
Yes, that claim was so effective back then that even JavaScript, which had nothing to do with the Java language, caught the same wind. Just as VB-Script was a subset language of Visual Basic, it was named Java-Script as if it were a subset language of Java.
Congratulations to Brendan Eich. For years, people who knew nothing about software saying, “Java and JavaScript are basically the same thing” became a running joke. There’s no such thing as bad publicity. That was one very slick trick. ;-)
After that little bit of gossip, let’s get to Kavak’s claim. MiniSwift and the other platforms have a three-year history. When I first started, I was looking for the answer to this question: if I drew SwiftUI code on a Web Canvas, could I achieve a stable 60 FPS? Later, I realized things weren’t going to work that way, and after three years of development and wandering away from quite a few goals, the project reached this point.
I won’t tell the whole MiniSwift story. The article would get too long, and it might get boring. After developing MiniSwift, I wondered whether I could apply the same approach to other languages. So I began experimenting with MiniKotlin and MiniSharp.
But things reached a point where I was writing the same code separately for every platform. Then I noticed something strange. Hang on—these languages’ STD Libs, meaning the basic functions they provide, were surprisingly similar to one another.
So what was I basically doing? First of all, the frontend.
Basically, I had MiniSwift, MiniKotlin, MiniSharp, and Metal as a bonus. In all of them, I first ran the language through a Unicode normalization process I had written myself. Then I tokenized it and created structs to give those tokens meaning. In other words, an AST.
let a = 1
Parsing “let, a, =, 1” is easy, but let is a constant, a is a variable, = is assignment, and finally there’s its type :D. The hard part is all that AST business. Every language has its own particular features. This is where they began to diverge, but no problem—I handled all of them. And honestly, this is the easy part.
IR (Intermediate Representation)
Well, well, well. What a cool name. I remember avoiding LLVM books for many years. Whenever my enthusiasm flared up and I visited LLVM’s website, I would spend thirty minutes there and then give up every single time, like an innocent villager who had just seen a UFO, thinking, “Nah, these guys are way too advanced in science,” or “How does this giant metal airplane even stay in the sky?”
Maybe LLVM’s website also has something to do with how intimidating it feels from a UX perspective, but 99% of the problem is me. Let’s not upset Chris Lattner, though—I already found myself grumbling his name with fond exasperation more than a few times while coding MiniSwift ;-)
There really isn’t that much to make a fuss about. Once you’ve managed to break the language apart, you need to turn it into an intermediate language however you please. A little effort, sleepless weeks, a whole world of problems, battles to achieve determinism, and then sweet relief ;-) That’s all there is to it.
Once you lower a language to the IR level, that language becomes yours. Do whatever you want with it. And rather than spending my limited time developing tools such as LLDB, I devoted it to solving the multi-platform and portability problem.
MiniSwift’s intermediate language is MIR. I didn’t think too hard about the name :D. Once I had lowered the language into this intermediate form, I realized I now had a very powerful weapon in my hands. Wait a minute—could I port this to Android? At first, I naively tried translating it into Kotlin, but I quickly abandoned that mistake. Because Swift → IR → Kotlin → Java—oh boy :D. That’s a copy of a copy.
Swift → IR → C
So I chose this route instead: Swift → IR → C. That’s it. Once I established the C bridge through JNI, bingo. I managed to compile the Swift project for Android without any problems.
But how was I going to prove this? Now that was a very difficult question. It must have been around three months before July 26, 2026, the date this article was written. I downloaded roughly 1,500 random XCode projects written in Swift from GitHub and compiled them from beginning to end with MiniSwift.
Within seconds, I managed to compile around 800 of them for Web, Native—(by Native, I mean Windows and Linux here. Yes, it gets a little silly, but between Mobile, Web, and Desktop, my brain is getting a bit fried, so please forgive me)—and Android. This was a huge achievement for me.
The remaining 700 were due to frameworks I didn’t support at the time, such as SwiftData, CoreData, SpriteKit, and CoreImage, all of which are now available in MiniSwift. I haven’t rerun the tests because I’m now chasing a bigger goal: the Kavak Multi-Platform Solution.
UI-IR (UI Intermediate)
Knowing my place, let me get back to the subject ;-). What I did with UI-IR became a complete turning point for MiniSwift. Remember how I said at the beginning that I had been thinking of a simple solution—whether I could turn SwiftUI into a canvas? Well, this is what came out of it.
SwiftUI is a declarative structure, as we know. I can’t call it a language. It reminds me a little of an HTML-like structure. Yes, for a solution to count as a programming language, it needs to have if-else. Does SwiftUI have that?
Anyway, I transformed SwiftUI’s declarative structure into my own intermediate UI-IR struct. But there was a problem. Turning only SwiftUI into an intermediate language was just one part of the job, because SwiftUI itself is in very close communication with the Swift language. At that point, getting my own MIR—MiniSwift IR—to communicate with UI-IR was enough for me to reach the solution.
Now, regardless of the language, because the Combine Framework was converted into IR together with the Swift code, it became able to communicate comfortably with UI-IR. It turned into a very sweet solution, because the SwiftUI code I wrote with Combine began working identically on Android and the other platforms :D.
Woo-hoo! Suddenly, I felt like this:
So how did SwiftUI UI-IR become able to run on the other platforms? You might say, “Okay, brother, we get it—you somehow translated the language, but how does that part work?”
Let me explain right away. After extracting the UI-IR struct, I used Figma to take each platform’s designs from their SVGs. Then I began replacing them with the interface code of whichever platform I wanted.
Of course, there was one small difficulty at this point. If a component that existed in SwiftUI didn’t exist on Android or the other platforms, I did a little welding in between and wrote that component at that point. I think that much cheating is acceptable ;-)
Other Multi-Platform Solutions
In general, when we developers are looking for a solution and a version of it has already been made, we can become a little discouraged. After all, there’s already React Native, Flutter, and now practically every platform—even .NET—claims it can produce output for iOS.
I never lost hope at this point, because that approach felt wrong to me. Here are the reasons:
- When someone already has a project and a language they’ve developed, you tell the person who will use your platform, “Brother, forget the language you know and the project you’ve developed. Come and rewrite it from scratch in Dart.” Sure, right away. :D
- Perhaps the solutions are simply too conventional. Flutter, .NET, and so on build this on top of ready-made engines such as SKIA, then say, “Well, here you go—it runs on every platform.” But I don’t like that part, because it isn’t native.
This is also partly because of my own approach. SML (sml.run) is an anonymous, end-to-end encrypted messaging application for both one-to-one and group conversations, using PQ, MLS, and DoubleRatchet, which I developed myself. I followed a similar approach there. Almost all of the code was written in C. Only the UI code at the top was separate. So I only needed to write UI code for Web, Android, iOS, and Desktop.
So, long story short, what I’ve actually done is this: Think Different ;-)
Final Word
Let me wrap things up now, because the longer this gets, the more boring it can become, and the harder it can be for me to explain what I mean.
Kavak is moving confidently along the path toward becoming a multi-platform solution. Over time, I’ll explain the thinking behind it at length again.
Take care ;-)