This content originally appeared on DEV Community and was authored by Mr Punk da Silva
A new project called Carbonyl takes a fresh stab at text-based browsing by forking Chromium and re-routing its rendering pipeline into a terminal emulator. Rather than outputting pixels to a window, Carbonyl maps every web page onto Unicode block characters and ANSI color escapes—complete with interactive text capture and input support.
Coverage on CyNews: https://cynews.vercel.app/show/45133935
Project page & write-up: https://fathy.fr/carbonyl
Background
Most terminal-based browsers rely on parsing HTML and re-implementing layout (e.g. w3m, lynx). Carbonyl instead leverages the real Chromium engine:
- It hooks Skia’s bitmap and text-drawing devices to capture rendered output.
- It preserves the exact layout, CSS, JavaScript engine and extensions you’d see in Chrome.
- It translates that output into terminal control sequences on the fly.
The result is a “true” Chrome experience—minus the GUI.
Rendering Pipeline
HTML → Skia bitmap
Chromium’s renderer draws pages into an offscreen SkBitmap. Carbonyl intercepts this via a customHostDisplayClient
and shared memory mapping between GPU, renderer, and browser processes.Bitmap → Terminal blocks
Each terminal cell uses U+2584 (lower half block) with 24-bit ANSI colors. Carbonyl sets the cell’s background to the top pixel and foreground to the bottom. It batches calls for minimal cursor movement:
fn print_pixels_pair(top: RGB, bottom: RGB, cursor: (x, y)) {
move_cursor(cursor);
set_background(top);
set_foreground(bottom);
println!("▄");
}
-
Text capture
A
TextCaptureDevice
, inserted into Skia’s pipeline, intercepts glyph runs. It converts glyph IDs to Unicode and issues ANSI code to render characters instead of bitmap blocks—preserving crisp text and selectable content.
Input & Interaction
Carbonyl listens for mouse and keyboard via ANSI Device Control Sequences (DCS). For example:
fn report_mouse_down((x, y): (usize, usize)) {
write!(stdin, "\x1b[<0;{y};{x}M");
}
These sequences feed events back into Chromium’s input system on the main thread via BrowserMainThread::PostTask
, enabling clicks, scrolling, and text input—just like in a GUI browser.
Performance & Tuning
Out of the box, Carbonyl renders at about 5 FPS with ~400 % CPU usage on a modern laptop. Two key optimizations were introduced:
- LoDPI scaling: For terminal output, the display scale is forced to 1/7, reducing the pixel grid by a factor of 49.
-
Threaded compositing hacks: Disabling
--disable-threaded-scrolling
and--disable-threaded-animation
keeps rendering on the main thread, avoiding expensive cross-thread coordination.
With these tweaks, idle CPU usage drops to near zero, and scrolling stabilizes around 15 %.
Community Feedback
On the CyNews discussion, developers highlighted:
- Novelty: “Finally, a real Chromium-powered terminal browser.”
- Performance concerns: CPU overhead makes it impractical for daily use today.
- Potential use cases: Remote servers, CI log previews, low-bandwidth environments, or ultra-portable dev setups.
- Feature requests: True-color detection, configurable block resolution, SSH-friendly input modes.
Why Carbonyl Matters
Carbonyl demonstrates how far browser engines can be repurposed when paired with terminal graphics tricks. It:
- Preserves exact web compatibility (JS, CSS, extensions).
- Maintains selectable text for copy/paste or accessibility readers.
- Opens a path for GUI-less demos, remote interaction, and embedded deployments in constrained environments.
For anyone curious about browser internals, terminal graphics or building bridges between GUIs and CLIs, Carbonyl is a compelling, hands-on case study.
Project write-up & demo: https://fathy.fr/carbonyl
Read the CyNews article: https://cynews.vercel.app/show/45133935
Let me know if you try it—what pages render best, or how it fits into your remote workflows!
This content originally appeared on DEV Community and was authored by Mr Punk da Silva