Hello friends! In June, Ladybird gained several things it couldn’t do before: you can now download files, browse and search your history, inspect cookies and storage in DevTools, and change video playback speed. Under the hood, our services started running inside real security sandboxes on Linux and macOS. Here’s what we’ve been up to.
Welcoming new sponsors
Ladybird is entirely funded by the generous support of companies and individuals who believe in the open web. This month, we’re excited to welcome the following sponsors:
- Paul Copplestone with $10,000 (renewed sponsorship!)
- SerpApi with $5,000 (renewed sponsorship!)
- Zeroramp with $5,000
- Kinde with $5,000
- Sjors Witteveen with $1,000 (renewed sponsorship!)
- publicqi with $1,000
- All Things Secured with $1,000
We’re incredibly grateful for their support. If you’re interested in sponsoring the project, please contact us.
Downloads
Ladybird can now download files! There’s a toolbar indicator with a popover showing active downloads and progress, an about:downloads page, cancellation, and a confirmation prompt if you try to quit with downloads in flight (#10335).
Downloads are managed in the UI process, so a download keeps going even if you close the tab that started it.
Browsing history
There’s now an about:history page that lists your local browsing history with search and the ability to delete entries (#10038). Internally, browser history now lives in the UI process (#10085).
Right-clicking or long-pressing the back and forward buttons now shows a native history menu, with saved titles and favicons (#10128). There’s also a keyboard shortcut to clear browsing data, along with deep links into the relevant settings dialogs (#10262).
DevTools: storage, styles, and scripts
Our DevTools gained a Storage tab this month: you can inspect and modify cookies (#10035), browse and edit localStorage and sessionStorage (#10055), and inspect IndexedDB databases (#10143). CSS rule inspection also landed, showing the individual declarations behind a computed value, with overridden ones struck through, invalid ones flagged, and working jump-to-source links including for user-agent styles (#9869):
There’s also a new script sources view with pretty-printing, folding, search, and jump-to-definition (#10195).
Media: playback speed and muted autoplay
You can now change media playback speed (#9925). Audio is time-stretched using Chromium’s WSOLA algorithm, so the pitch stays put and speech stays intelligible whether you speed a clip up or slow it down. Here it is at a few different speeds, with sound:
Muted media can now autoplay by default (#10014). The old autoplay setting was all-or-nothing and blocked everything, including silent background videos, which left a lot of sites looking broken. It’s now a tri-state policy that allows inaudible media to autoplay while still keeping audible playback gated behind a user interaction, so unmuting or calling play() can’t sneak sound past it.
| Before | After |
|---|---|
Security and hardening
We spent a bunch of time in June making Ladybird harder to attack.
- Sandboxed services : Helper processes now run inside real sandboxes on Linux and macOS, using seccomp/Landlock on Linux and Seatbelt profiles on macOS (#10001, #10042). Sandboxing is now on by default (#10132).
- Heap partitioning : String data, ArrayBuffer backing stores, and JS object property storage now live in dedicated heap partitions, keeping unrelated data away from security-sensitive state (#10041, #10025, #10033).
- Fuzzing fixes : We fixed a batch of fuzzer-found crashes and undefined-behavior issues across DOM, layout, image decoding, and CSS pixel math (#9959, #10100, #10110, #10217, #10249).
- Memory-safe decoding : Text encoding/decoding moved to Firefox’s Rust-based encoding_rs, and GIF decoding moved to Wuffs (#10204, #10031).
- Canvas isolation : Cross-origin image data is now tracked for canvas tainting, and
toDataURL()/toBlob()are rejected on tainted canvases (#10094, #10013).
GPU access moves into the sandboxed compositor
Last month we moved the compositor, the part of the browser that assembles and paints the final pixels you see on screen, into its own process. This month, canvas and WebGL rendering moved across the same boundary. 2D canvas command lists are now replayed and rasterized in the compositor (#10086, #10133), nested contexts rasterize during replay (#10194), and WebGL commands are streamed over shared memory (#10269).
The payoff is security as much as architecture: WebContent processes no longer need direct GPU access (#10154, #10156). Pinch-zoom is also handled asynchronously on the compositor, so zooming stays responsive even when the main thread is busy (#10120).
Down to a single JavaScript interpreter
LibJS now runs its optimized assembly interpreter on every platform, after enabling it on Windows (#10093). That let us delete the older generic bytecode interpreter entirely and consolidate on a single one (#10099), leaving one code path to optimize and maintain from here on. JavaScript strings also moved to UTF-16 throughout, matching how the language defines strings and removing a lot of conversion churn (#10231).
WebAssembly GC
LibWasm gained support for WebAssembly GC, along with some of the exception-handling proposal (#10130). Wasm GC adds garbage-collected struct and array reference types, which a growing number of toolchains (for languages like Kotlin, Dart, and Java) target when compiling to WebAssembly. The Cranelift-based JIT from last month also got a round of fixes, including correctness fixes and getting it working under our benchmark harness (#9813, #9878, #9906).
CSS features
- Container-relative units :
cqw,cqh,cqi,cqb,cqmin, andcqmaxare now supported, building on last month’s container queries (#9721). -
contrast-color(): Thecontrast-color()function is implemented, picking black or white for legibility against a given background (#9920). - Registered custom properties :
@property-registered custom properties are now computed according to their declared syntax (#10254). -
progress(): Theprogress()math function is implemented (#10181). -
anchor()incalc():anchor()can now be used insidecalc()expressions (#10108).
Browser UI
- Tab hover previews : Hovering a background tab now shows a thumbnail preview, built from the cached WebContent bitmap so it doesn’t trigger a repaint (#10049).
- macOS IME : Input method editor support now works in web content on macOS, so CJK and other composed input behaves as expected (#9756).
- Autocomplete and window behavior : A cluster of fixes around the location editor and macOS window handling, including better autocomplete dismissal and frameless-window resizing (#10220).
- Vertical tabs : The vertical tab strip can now be positioned on the right (#10198), and shows audio and close icons on collapsed tabs (#9829).
Some sites that work better
tweakers.net : Implementing contrast-color() fixes the unreadable text in the orange banner (#9920).
| Before | After |
|---|---|
![]() | ![]() |
rubyllm.com : The site’s logo uses a CSS content image that only appears in dark mode, which now renders correctly (#10273).
| Before | After |
|---|---|
![]() | ![]() |
rightmove.co.uk : Allowing transforms on pseudo-elements cleans up box artifacts in the navbar, which are supposed to be transformed into arrow shapes (#10116).
| Before | After |
|---|---|
![]() | ![]() |
A pair of table layout fixes found on an online crossword cleared up badly overlapping cells (#10306):
| Before | After |
|---|---|
![]() | ![]() |
A few more:
- WhatsApp Web no longer shows the “unsupported browser” dialog and reaches the QR login screen (#10297).
- Transfermarkt no longer crashes on navigation (#10291).
- npmx.dev : Two grid layout fixes (#10190).
- chatgpt.com : Reduced redundant style invalidation work (#10067).
- GitHub : Faster hovering over links in long pull request lists (#9979).
Web Platform Tests (WPT)
Our WPT score went from 2,075,546 to 2,078,912 this month, a gain of 3,366 subtests.
Other notable changes
- Web Locks API : Initial support for the Web Locks API landed (#10261).
- Presentation-aware emoji fonts : Emoji font fallback now respects
font-variant-emoji, and emoji text-shadows paint in the shadow color (#10192, #10168).
A note on our development process
In June we also changed how code enters Ladybird: it’s now maintainers-only, and we are no longer accepting public code contributions. Ladybird remains open source, and outside involvement still matters through bug reports, reductions, website testing, standards discussion, and security reports. We laid out the full reasoning at the time in Changing How We Develop Ladybird.
That’s it for June. Step by step, we’re getting closer to our first alpha. Thanks for reading, and we’ll see you next month!







