Dinnerbone
•
2026-11-04
Well, we said we'd make these posts more often... it's been over two years since the last one! We'll come up with a poor excuse for our absence at the bottom of the post, but we're hoping that all these really cool changes will distract you from that!
As always, let's summarize with some fancy numbers before we get into any of that.
Since the last blog post (over 2 years ago)...
A frequent request over the past few years has been to make less frequent, stable, releases - and thanks to the work of @kjarosh to finish up all the loose ends, we're finally there.
In fact, we're now on version 0.7.1 at the time of writing this! We've had quite a few stable releases since the first one back in May to prove out the system, so it's about time we actually announced them!
Stable releases do not have a fixed frequency, and will mainly drop when we feel that enough has changed to warrant a new version, and that we're feeling reasonably confident in the stability and performance.
We'll still release nightlies for those brave souls who are willing to test things ahead of time and want to help us find and fix bugs, but we do recommend that users switch to stable releases if they, frankly, just don't want the fuss.
Our desktop app does not auto update by itself, so you'll still need to manually download either the stable or nightly releases whenever you wish to update. You can find the links on our download page. For Linux users, our Flatpak app updates automatically for stable releases. We also now provide Linux ARM64 and i686 builds!
We've changed the official store releases of our extensions to use stable releases, nice and easy. If you want stable releases, there's nothing to do here, hurray! If you do want to live on the bleeding edge, you'll have to manually download and install the nightly version of the extension. They do not self update, so we do not generally recommend this outside of testing.
The self-hosted version of Ruffle is available in both stable and nightly versions on our download page, as normal.
If you installed Ruffle onto your website through our recommended <script src="https://unpkg.com/@ruffle-rs/ruffle"></script> tag, you're now using stable releases. Hurray!
If you want to stay on the bleeding edge, though, swap that to <script src="https://unpkg.com/@ruffle-rs/ruffle@nightly"></script> instead.
The Android app is technically a separate project and is not affected by the stable releases. If there's demand for this, we'll look into it - but we also want help maintaining it!
Speaking of apps, @madsmtm has been working on an iOS app! It's still a work in progress but worth checking out.
In early versions of Ruffle, we just started putting methods and properties on the <ruffle-player> element itself. Turns out, this wasn't so smart, and we ended up conflicting with the ExternalInterface API and Flash's own (mostly undocumented) API.
To fix this, we've added a .ruffle() API that we recommend using instead. This mostly means using foo.ruffle().load() instead of foo.load(), but the full API can be found on our JS docs.
This API is versioned; if we ever need a v2, we can .ruffle(2). The previous API still exists for compatibility, but we do not recommend its use for newer code.
You may have noticed that whilst our "ActionScript 1/2 Language" percentage has crept its way up to 99%... We're pretty proud of that! Unfortunately, we're very much in the "90/90 rule" area.
The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.
We've made many incorrect assumptions during the early days of our AVM1 implementation which we're trying to correct now in the final 1%. We can confidently say that almost every real world movie will work, but we're constantly finding areas that we would not match Flash, and trying to fix those is difficult.
The most notable fix here comes from @relrelb in #24725, which finally fixes the long standing issue in Super Mario 63 where the game is stuck on the final battle.
Other notable changes include:
loadVariables for non-movie-clip targets (#19467).Point and AsBroadcaster from Rust to ActionScript (#24873, #24736).super to NativeObject, finally killing off TObject (#19936, #20204).We've come a very long way since the early days when we had the infamous "ActionScript 3 is not yet supported" screen. You've been able to play almost any game in Ruffle with little issues for a while now, which is super cool!
However, as we've been focusing heavily on "getting it working correctly", we certainly are not as fast as Flash Player was, it's true. Our philosophy has always been to make things correct, add all the tests we can possibly think of, and then use those tests to make sure that any optimizations we do are correct and stable.
All that said - the fantastic @Lord-McSweeney has been hard at work improving the performance of AVM2 content in Ruffle, almost all of which also bring some bonus bug fixes:
PrimitiveObject (#18995).We've also been working on general fixes and improvements, for example:
Dictionary match Flash's "JIT mode" behaviour for QName keys, fixing a black screen in Typing Maniac (#24890).Dictionary, fixing save games in Reactance 2 and Muse Quest (#21428).Context3D methods, fixing Tamagotchi Friends: Dream Town, Zombidle and Mutant Fighting Cup 2 (#22077).RegExp features, fixing Castle Wars 2 (#20426).ByteArray.compress more accurate to how Flash compresses things, fixing progress not being saved in GemCraft Labyrinth (#18366).scrollRect, fixing the inventory cursor in The Enchanted Cave 2 (#24475).Array.splice, which fixed Dynapuff Jump (#23197).URLRequest with an empty body perform a GET, matching Flash (#20242).Graphics's gradient APIs (#18699).BitmapData.histogram, fixing BoxHead: The Nightmare (#18075).A frequent topic on these blog posts, it turns out that text rendering is hard... Who knew!
TextField.styleSheet (CSS-like) support, as used by Transformice and Dead Maze (#19143).TextField AVM2 scroll event (#24625).<img> tag parsing/serialization (#24802).We've had many bugs with sounds, especially older AVM1 games. Thankfully, we're significantly better than we were 2 years ago – no more sudden loud noises here!
SoundTransform apply before playback (#22154).Sound.loadSound() (#23975).new Video(0, 0) use the default video size, matching Flash (#23708).It's hard to overstate how many improvements have been made to our rendering pipeline, but the biggest change of all has to be that we now finally support hairline and scaled strokes. Thanks to the hard work of @darktohka in #23011, many games and movies now look true to how they did in Flash, and not just "crazy thick lines" all over the place. Hurrah!
Other notable improvements include:
BitmapData.draw, fixing rendering in Fireboy & Watergirl 2 and 3 (#21624).surfaceSelector in Context3D.setRenderToTexture (#15495).Context3D.setStencilReferenceValue & Context3D.setStencilActions (#20875).Matrix3D (#18888).copyPixels degrading opaque pixels, which made it impossible to progress past level 4 of Toxic 2 (#24492).colorTransform out of bounds, as seen in Mega Mash (#20363).DisplayObject.z, making games like Hexagon playable (#19405).The desktop application has been getting a little love, with a focus on better RTL and CJK support. We're not entirely done yet, the IME support is still a work in progress, but it's certainly getting there!
Ruffle is used on so many websites now, including the Wayback Machine (does that count as us being on every website?). We've also surpassed over 1,000,000 active users on our Chrome extension alone, which is absolutely astounding!
fpdownload.adobe.com (#22168).Don't let the lack of specificity fool you, these fixes are just as important as all of the above, perhaps even more so – it's just hard to group them together! ;)
AVM1Movies around, fixing SpongeBob Decorating Dilemma freezing on its loading screen (#21528).goto actions overwrite prior gotos, fixing a bug with Epic Battle Fantasy 4 (#20254).goto bug with SWF9 (#22408).play/stop actions whilst queueing gotos, fixing Gacha World, Tomb Chess and William and Sly (#24684).gotoAndStops in SWF 9 & SWF 10, fixing the medal graphics in Super Crazy Guitar Maniac Deluxe 2 (#24741).ImportAssets bug by pausing preloading until imports finish (#16968).ImportAssets bug with executing DoInitAction code with the proper context, fixing Cubis 2 (#21944).hitTest on the edges of shapes, fixing characters falling through floors in Castle Cat and Powerfox (#20811).BitmapData.hitTest with 0 alpha threshold, fixing collision issues in Super Smash Flash 2 (#23870).SharedObject (#18046).goto'd frames are made, fixing games such as Road of the Dead or Wedding Trouble (#22677).We're extremely proud of our tests in Ruffle, with over 500 unit tests and over 4500 conformance tests (often consisting of dozens or hundreds of smaller tests). That's a 60% increase in tests since our last blog post! We're firm believers that any investment into test frameworks will always be worth it and pay off, and in a world where more people are throwing automation at problems, tests help keep the slop at bay.
Since the last blog post, we've had over 170 PRs aimed directly at our tests, excluding all the regular PRs that happen to include tests. Here are some notable improvements:
BitmapData (#22149).Okay, I'll drop the royal "we" and take responsibility here. I kept pushing off a blog post because of time, energy, and fatigue. I've been working on Ruffle for 7 years now. I love this project, I'm extremely proud of everything we've accomplished, but it's hard for me to stay dedicated for that long. I've gone through my share of burnout, it sucks, and so whenever I feel myself getting close I take a step back and treat myself to a long break. I've taken a fair few breaks since the last blog post, and other amazing contributors and maintainers have stepped up to keep things running, but the blog post kept waiting for me to come back and finish. Every time I thought about it, it was a bigger and more daunting task, and it became something of a vicious cycle - putting off the scary thing because it's been put off and made scarier. A tale as old as humanity!
I already anticipate some "Why not let AI write it for you?" in some discord thread or comment section, so I will address that up-front: Frankly, I'm no friend of LLMs. I especially do not believe it has a place writing articles and blog posts. If you wanted just the facts, ask your friendly local LLM to do that - it might even be correct. If you want what we, the maintainers, think and feel - you need a human to write that.
This isn't a section I anticipated writing when I wrote the last blog post, but the future sure is weird.
The rise of LLMs has certainly been a thing, and I'm sure you don't need yet another blog post prophesying doom or raining blind praise. However, I do think it's fair to talk about how LLMs have affected us as a project, especially with the "decompile everything" trend that is happening.
Being completely honest - it's not great, but it's not the end of the world either. We've had some genuinely useful and helpful contributions aided by LLMs, and I do believe that at some tasks, it is becoming okay, with the right guidance and someone to shepherd it and take responsibility for its actions. However, with every useful change we get a dozen not-so-useful ones, and with a project that values correctness above all else, it's extremely hard to trust a tool that hallucinates behaviours.
We have largely adopted the LLVM AI Tool Use Policy (with a few project-specific rules), which mostly boils down to "a human must be in the loop". For the correctness of our project, for the quality of our code, and for the sanity of our maintainers - we need people to be able to understand, and take responsibility for, the output of their tools. It's hard to imagine projects thriving where that isn't true.
It's worth noting that our PR backlog is long, and it rises every day. It's very easy to create a dozen pull requests, but each one requires more effort and time from our maintainers than it did for someone to create them. Maintainer burnout is real, and it's becoming a serious problem. It's not solely due to LLMs, of course, but it's certainly the biggest factor as of writing this post. This is a problem that affects the entire open source community as a whole, not just Ruffle, and there's no solution in sight. Be kind to your local OSS maintainers! :)
I'm so very proud of how far we've got with Ruffle, and I know that it only gets better from here. Thank you to everybody who helped keep Ruffle alive throughout these crazy times, and see you in the next post!
As a reminder, Ruffle is a completely open source project and we're always looking for contributions! Some quick ways to help out:
Thank you all again, and see you in the next blog post! <3