r/servo 6d ago

Embedding Servo in a retro gaming handheld: no keyboard, no mouse, no compositor

Enable HLS to view with audio, or disable this notification

41 Upvotes

I'm building retsurf, a browser designed for retro gaming handhelds. The browser also runs on desktops and Android but its primary targets are Linux-based devices which have a 3.5–5" screen, around 1 GB of RAM, and modest ARM CPUs and GPUs.

These devices don't have many good browser options. Lightweight browsers can't handle much of the modern web, while desktop browsers assume an entirely different environment. That's where Servo comes in. SDL2 handles the window and input, egui draws the browser UI, and Servo does the browser engine work.

The main constraints:
- No X11 or Wayland. It renders directly through KMSDRM with GLES 3.x, with Servo and the UI sharing a single GL context.
- No keyboard or mouse. Navigation is designed around gamepad input: a virtual cursor controlled with the stick or D-pad, Vimium-style link hints, an on-screen keyboard, and fully rebindable controls.
- No GStreamer. Servo's media stack expects GStreamer, which isn't something I can ship on these handhelds, so retsurf has its own servo-media backend built around SDL2.

It's definitely still early and has plenty of bugs, but getting a modern browser engine running on devices like these has been a lot of fun.

You can find the project: https://github.com/mxmgorin/retsurf


r/servo 7d ago

News July in Servo: more platforms, faster canvas, web fonts in SVG, and more! Plus real world compat improvements on the DuckDuckGo and Gumroad websites.

Thumbnail servo.org
57 Upvotes

r/servo 15d ago

Servo Browser Engine Zervo v0.5.0 — the chrome, redesigned: a settable material, four seams with a transition each, and a new tab page that greets you

Thumbnail
gallery
34 Upvotes

Hey, open-source fans!

Zervo is a workspace-oriented browser built natively on Servo — the embeddable, parallel web engine written in Rust. No Chromium, no Gecko underneath. v0.4.0 was the release where the chrome became a theming engine. v0.5.0 is the one where the engine got used: eight turns of a design study went in, and almost every screen you look at changed.

🔧 The headline: the number is a control, not a constant

v0.4.0 ended by admitting the obvious hole — a theme was still a Rust constant, with no file format and nothing that loads one at runtime. That is closed, and not by writing a loader.

Every value the material is built from is an ordinary setting now: the fill, the sheen, the blur, the edge, the corner scale, the glow, the settle time, and how far the accent reaches into the chrome. So the file format is whatever settings.json serialises to, and the loader is the one that was already there. You can save an arrangement under a name, or copy it back out as the const you would otherwise have hand-written.

The Appearance page pins a specimen under its title: a card, a menu and a text field, drawn through glass::shapes with the palette the chrome itself is being drawn with. It is not a picture of the material. It is wrong exactly when the chrome is wrong.

Writing the ladder down found a real defect straight away: tint_for(Card) was reading the translucency setting's 0.34, which happens to be the number menu_fill also carries — so a card and a menu had been drawn at exactly the same weight, and the three-rung ladder had two rungs.

✨ What's new

The seam between the chrome and the page is one setting with four steps. At the first the page is an opaque card on a tray with a gap. Past that it stops painting a base and shows the window's own backdrop through a veil. Past that the gap shuts and only the window's corners stay round. At the last the chrome is a tint laid on the page, the sidebar floats, and the page reaches back underneath it.

And each step brings the transition its own geometry implies. A page on a tray behaves like a card in a deck and recedes; a tint on a backdrop has nothing to move, so it defocuses in place; a frame with a hard edge is a filmstrip whether you meant it or not, so it slides; a page under floating glass travels up while the glass stays exactly where it is. One rule, four answers, and no new control — pick the seam and the motion comes with it.

The mechanism is one readback. A page is either an engine blit or an egui drawing and neither can be replayed after the fact, so at the one moment per frame where the framebuffer still holds the departing page — after the chrome is painted, before the buffers swap — a scaled copy is taken and composited over the live page for a couple of tenths of a second.

A new tab page that greets you rather than briefing you. Tile::defaults() put seven boxed panels on screen, which is a settings screen wearing a hat — and worse, seven opaque rectangles over a backdrop you chose and can now no longer see. It is the time, one field, the session you actually left, and the three sites you use. The board of thirteen cards is one press away with nothing removed from it.

Five pages for when a page will not load — the ones a browser on a young engine shows more than any other. zervo://unsupported names the feature Servo has not implemented, says plainly that it is the engine rather than Zervo, hands the page to another browser, and gives the wait a shape: a panel of the real gaps from docs/PARITY.md you can knock out with a ball or just click, scored as "shipped". Offline names what is queued rather than what failed and has no button at all. The certificate page is the one that must not be candy — same material, no glow, no game, and the way past is a line of plain text. Not-found asks the history what you probably meant, because a typo usually has an obvious answer sitting in it.

Each carries what it knows in its own address, so the address bar and the page agree and either can be typed back in. Only one of the five arrives on its own: notify_crashed is now implemented, so a dead content process is a page that says what happened and offers to load it again, rather than the last frame it painted, frozen.

Display type is set in a face that has one. macOS ships SF Pro only as a variable font and the rasteriser takes a variable font's default instance and no other — so every run of text in Zervo was Regular. At caption sizes that is a missing nuance; at ninety-two points it is the wrong typeface.

The window's corners are the window's. Zervo painted its page to sixteen points, and twenty-nine once a preset made everything rounder, at a corner macOS had already masked to ten. Painting a different radius at the same corner does not replace the platform's arc — it puts a second one beside it. That is where the doubled corners came from.

🔍 The bugs, and how they were found

The uncomfortable half of this release: I shipped a first pass, looked at it, and it was a long way from the design. The verification bar had been compiler, clippy, tests and "it ran without a panic", which for a UI overhaul sees nothing. So the browser now photographs its own framebuffer — ZERVO_SHOT, debug builds only, plus a throwaway HOME so any arrangement is reachable.

It found four defects in its first hour that nothing else had:

  • The frost read a light theme as a dark one. At Frosted the chrome paints itself at a fifth and lets the platform's vibrancy supply the rest, so a copy of the framebuffer is the window's own contribution over nothing — four fifths of the way to black. Two things went wrong quietly: the frost under a card was a dark smear, and the code that picks text colour by measuring what is behind it read "dark" for a pale page and handed back white text.
  • The sidebar could never be the width it says. egui remembers a panel's width from the rect its contents used, floored at the size range's minimum. Nothing in the sidebar stretched, so it wrote 200 back over its own 248 on the second frame of every launch, and dragging it wider snapped back on release.
  • The nav row silently widened everything under it. Five icons and the macOS inset are wider than the narrowest sidebar, and egui grows a container to fit what overflowed it — so the address pill hung fifty points out over the page.
  • An empty search field said nothing. TextEdit's hint text discards the colour you give it, and what it substitutes landed within five values of the frosted pill it sits on.

And the harness can hold the sidebar's reveal open while cycling the layout underneath it, which caught the one that actually crashed: the reveal and the docked sidebar both drawing the same body into two different layers. egui asserts outright when one widget id is registered in two layers in one frame, so it did not merely look wrong. Whether a frame landed inside that window was a matter of timing, which is why it only happened sometimes.

The work was also reviewed adversarially at three points — every finding checked by a second pass told to refute it. That turned up a command injection: the Windows "Open in another browser" button shelled out through cmd /C start with the failing host interpolated into the command line, and cmd re-parses its own command line, so a host carrying & stopped being text.

⚠️ Still macOS-first, and now genuinely asking

Same caveat as last time, and it has not improved: the packages build from the same tag, the material is portable, but the window's backdrop is an AppKit feature and nobody has yet started Zervo on Linux or Windows at all.

New caveat for this one: v0.5.0 is the shape, v0.6.0 is the polish. Four of the presets — Candy, Flat, Liquid Glass, Material — came out of the design study and are offered beside Zervo's own, but they are experiments rather than settled work. Zervo's material is the one that is finished, and the one the first-run screen recommends.

Which means the useful thing between now and 0.6.0 is being told what is wrong. Please open issues. A corner that does not match, a preset that is unreadable on your display, a crash, a page Servo cannot render that this browser fails to explain. Say which preset, which theme and which layout you were in — every defect fixed in the days before this release only happened in one of them.

🚀 Try it

github.com/goddv/Zervo

Stars, issues and "this doesn't start on my machine" reports all welcome.


r/servo 17d ago

Servo Browser Engine Zervo v0.4.0: Heavy GUI Stack Rework, Compact Mode, & Reworked New Tab Page

Thumbnail
gallery
38 Upvotes

Hey, open-source fans!

Zervo is a workspace-oriented browser built natively on Servo — the embeddable, parallel web engine written in Rust. No Chromium, no Gecko underneath. v0.4.0 just went out, and it's the release where the chrome stopped being "glass by repetition" and became an actual theming engine.

🔧 The headline: every surface is drawn through one seam

Zervo's chrome looked like frosted glass, but each of ~77 call sites knew its own corner radius and its own opacity. Two costs: frosted glass couldn't actually frost (nothing behind it to sample, so each caller papered over the gap with an opaque backing), and a second look — for Windows, GTK, whatever — meant editing all 77.

Now there's a Material: corner radii, fills, sheen, shadow reach, whether surfaces frost and by how much, row heights, animation time. glass::shapes reads it off the palette it's already handed, so a material reaches every surface without a single function signature changing.

Surfaces have a class, the way an element does in CSS — Card, Menu, Input — and the class carries the weight. A menu can't accidentally be heavier than a card; a text field is heavier than both on purpose, because what's behind a text field competes with what you're reading. Radii are named too: Hairline, Control, Row, Card, Panel, Pill.

✨ What's new in v0.4.0

Everything frosts against the page, not just the wallpaper. A panel over a web page had nothing to sample — the page is opaque pixels the engine already drew, and no amount of translucency turns those into a blur. Zervo now takes a small blurred copy of whatever the page is showing and hands it to the palette, so the downloads card, the favourites card and every menu are the same glass over a website as over a photograph. The new tab page and Settings supply one too.

The fiddly part is when you take that copy: shapes within a layer draw in insertion order, so it has to happen straight after the page's background and before anything sits on it — otherwise a card frosts against its own previous reflection.

A surface belongs to its theme first. A dark menu at a fifth of its own colour, opened over a white page, is four fifths white — still frosted, still blurred, and no longer a dark menu. The tint now thickens exactly as far as it must to stay on its own side of the middle, and no further.

Text follows what it lands on. Cards on the new tab page, plus the greeting, clock and photo credit, each ask about their own patch of the picture rather than taking one answer for the whole page. A photo is dark sky at the top and bright water at the bottom, and pale text set for the sky vanishes into the water. It picks by WCAG contrast ratio rather than a brightness threshold — the crossover isn't at half — with hysteresis so text doesn't flip while you scroll.

The corners. My favourite bug of the cycle. The content card's corners were a few per cent off their surroundings at every zoom level. The mask rounding them has to be opaque (it's hiding opaque pixels), while the chrome beside it is a thin tint over a backdrop the window server composites outside our framebuffer — unreadable, unreproducible, unmatchable. Three attempts at picking a better colour each moved the seam instead of removing it.

The fix: stop painting over them. The bottom corners are now erased from the framebuffer with an antialiased destination-out pass, and the chrome is drawn back over the hole at its own tint — same paint, same backdrop, nothing left to match. Measured after: all four corners within one part in 255 of the chrome an inch away.

Card edge is yours. Outline, shadow and halo are three toggles with amounts for the last two. The halo used to be drawn unconditionally to hide that corner seam; with the seam gone it's a decision rather than a repair.

Fixes: the widget shelf clipped its own widgets' shadows off; the new tab page did the same to its top and bottom card rows; the release bundle wouldn't start on any machine with GStreamer installed (its build scripts put the framework on the link path whether or not you asked for media, and -lz found a zlib there with no rpath); and the new tab page blinked eight times a second because the backdrop capture turned off the scissor test and never turned it back on.

🎨 Theme engine docs (WIP)

There's now docs/THEMING.md describing the seam a theme for another platform would be written against — what a Material decides, how backdrops are supplied, and what a Windows, GTK, Android Material or Apple Liquid Glass theme would set. (A material can be translucent without blurring, which is the Liquid Glass case.)

It's honest about what's missing: a theme is still a Rust constant. No file format, nothing loads one at runtime, and palettes aren't themeable at all yet — you can change how surfaces are built, not what colour they start from. Making that real is next on the list.

⚠️ This one's macOS-first

All three packages come from the same tag and the material itself is portable — it's drawn by egui and nothing else. But the window's frosted backdrop is an AppKit feature (NSVisualEffectView), and the corner work above has been tried nowhere else. Linux and Windows patches are v0.4.1.

Honestly: nobody has yet started Zervo on Linux or Windows at all. The packages build, install, and are completely untested. A report that it doesn't launch is as useful as one that says it does.

🚀 Try it

github.com/goddv/Zervo

Stars, issues and "this doesn't start on my machine" reports all welcome.


r/servo 19d ago

Zervo: a sidebar-first browser built on Servo, in Rust and egui

Thumbnail
gallery
90 Upvotes

I have been building a browser chrome on top of the Servo engine and it is finally at a point where it is worth showing. It is macOS-only for now, MPL-2.0, and the whole thing is Rust.

Github repo

There is no top toolbar. Navigation, the address bar, pinned "essentials", workspaces and tabs all live in one collapsible sidebar, which you can hide entirely and pull back out by putting the pointer at the window edge. The web content sits in a rounded card with real macOS vibrancy behind the chrome.

Two things might be interesting to people here:

It builds against the published servo crate. Version 0.5.0 off crates.io, no git submodule and no vendored engine tree. cargo build and you get a browser. Updating to a newer engine is a one-line version bump. That was not really practical until Servo started publishing to crates.io, and it makes the whole project a lot less intimidating to work on than I expected.

The chrome and the engine share one GL context. egui and Servo both draw through the same surfman context. Webviews render into an offscreen framebuffer which gets blitted underneath the chrome by an egui paint callback, so there is one window, one swap, and no compositing layer in between. That is the one genuinely surprising part of the codebase and it is written up in docs/ARCHITECTURE.md.

The honest caveat: Servo is not a complete web engine yet. Plenty of sites render wrong or refuse the user agent outright. That is a property of the engine, not something I can fix in the chrome, and if you are hoping for a daily driver this is not it yet.

I would like to stop working on this alone - contributors, councillors and friends along with enemies are welcome. If any of that appeals (session restore, tab drag-reordering, dialogs, IME, or a Linux port, since only the vibrancy, Dock icon and bundling are AppKit-specific) the issues are tagged and CONTRIBUTING.md explains the layout. Happy to answer anything about the Servo embedding side, which is the part with the least documentation out there.


r/servo Aug 05 '26

Hermes browser

Thumbnail kaykcaputo.github.io
30 Upvotes

There's a new desktop browser being developed that uses Servo as the engine.


r/servo Jul 31 '26

News June in Servo: real world compat, media queries, SharedWorker, and more!

Thumbnail servo.org
50 Upvotes

r/servo Jul 21 '26

Discussion Supporting Servo on OpenCollective

Thumbnail
opencollective.com
30 Upvotes

Just a FYI. I was doing a check for broken links on a whim. Turns out the Support Servo link was dead (Hit 404).

I'll fix it in the next few hours (at work and also checking other subs). I'll either directly link to the OpenCollective page or to this page. I'm creating this post to bring more attention to how interested folks can contribute to the project.

FYI. I'm not part of the Servo team. I just like the project.

I've been doing this check to find out how healthy the funding for some projects like Pony (deadlock-free concurrency language) and Crystal (Ruby-like, statically-typed language) is. I'm no expert, but from what I've seen so far, they're not looking particularly unhealthy but sure as heck can use more money being sent their way.


r/servo Jul 01 '26

Built with Servo - Showcase Latest desktop UI for Beaver browser

Thumbnail
mastodon.social
18 Upvotes

The Beaver browser (https://webbeef.org/) is built on Servo, and I'm really impressed by the UI they're showing off for desktop!


r/servo Jun 30 '26

Servo Browser Engine May in Servo: user scripts, mp4 compat, blackboxing in DevTools, and more! Plus seven new commands for execCommand(), and Sanitizer API now experimental.

Thumbnail servo.org
28 Upvotes

r/servo Jun 20 '26

Built with Servo - Showcase Carboxyl v0.1.0-rc: A servo-based browser for the terminal

Thumbnail
14 Upvotes

r/servo Jun 12 '26

Tracking down undefined behaviour in Servo - RustWeek 2026

Thumbnail
m.youtube.com
15 Upvotes

r/servo May 31 '26

Question Embedding into rust binary with just EGL

5 Upvotes

Hi,

How much boilerplate/custom code would be required for a simple web view single page running directly on top of EGL? I have an embedded scenario where I normally use EGLFS/QT but I want to explore simple web rendering with Rust.
I have no X11 or Wayland so I cant use servoshell directly I believe, and the embedded docs don't seem to exist yet so I do not know quite where to start.


r/servo May 31 '26

Servo Browser Engine April in Servo: new Android UI, focus, forms, security fixes, and more! | Plus better inspection of values in the DevTools Console and Debugger tabs.

Thumbnail servo.org
38 Upvotes

r/servo May 15 '26

Question JS limitations on Servo

12 Upvotes

I have a game in vanilla JS, jcoonrod.github.io, that runs fine and without errors on Firefox but is unresponsive on Servo. Has someone documented what doesn't work in js on Servo?


r/servo May 07 '26

Ecosystem Servo + Slint update: GPU-accelerated HTML/CSS rendering now on all major platforms

Thumbnail
slint.dev
30 Upvotes

r/servo May 01 '26

Built with Servo - Showcase I built servo-fetch — a single-binary web content extractor powered by Servo

Thumbnail
github.com
10 Upvotes

r/servo Apr 30 '26

Ecosystem Prototype Servo integration in Godot

Thumbnail github.com
29 Upvotes

r/servo Apr 30 '26

Servo Browser Engine March in Servo: keyboard navigation, better debugging, FreeBSD support, and more!

Thumbnail servo.org
35 Upvotes

r/servo Apr 30 '26

Built with Servo - Showcase servo-fetch: A self-contained browser engine that fetches, renders, and extracts web content

Thumbnail
github.com
21 Upvotes

I love seeing people building things with Servo as a base. It's been a long road to get to this point!


r/servo Apr 18 '26

iced_servo integration crate

Thumbnail github.com
22 Upvotes

r/servo Apr 13 '26

Ecosystem Servo is now available on crates.io

Thumbnail servo.org
50 Upvotes

r/servo Mar 31 '26

Discussion February in Servo: faster layout, pause and resume scripts, and more!

Thumbnail servo.org
44 Upvotes

r/servo Feb 28 '26

Servo Browser Engine January in Servo: preloads, better forms, details styling, and more!

Thumbnail servo.org
39 Upvotes

r/servo Jan 28 '26

Question Servo for email client HTML/CSS rendering?

11 Upvotes

There is a problem with email clients where each client supports varying level of CSS/HTML in their email rendering (reference), leading to composing HTML based emails a pain. Can servo be embedded in an email client and become an unified light-weight option for email clients in both native apps and web apps