Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c2414db
Add Sixel rendering support
nbritton Sep 29, 2025
97f133c
Merge pull request #1 from Qubitdyne/codex/add-tier-1-support-for-six…
nbritton Sep 29, 2025
626cc65
Adjust sixel mode defaults and fix color comment
nbritton Sep 29, 2025
ee1fca9
Merge pull request #2 from Qubitdyne/codex/fix-sixel-rendering-positi…
nbritton Sep 29, 2025
6eecb74
Default to sixel rendering with scrolling
nbritton Sep 29, 2025
23ccb5a
Merge pull request #3 from Qubitdyne/codex/set-sixel-rendering-as-def…
nbritton Sep 29, 2025
696b842
Improve Sixel rendering geometry and options
nbritton Sep 29, 2025
83f6847
Merge pull request #4 from Qubitdyne/codex/fix-sixel-rendering-to-ful…
nbritton Sep 29, 2025
7541891
Default to sixel rendering
nbritton Sep 29, 2025
3c10ba5
Merge pull request #6 from Qubitdyne/codex/refactor-to-use-sixel-only…
nbritton Sep 29, 2025
b09b0d5
Fix warnings in window update logic
nbritton Sep 29, 2025
a241843
Merge pull request #7 from Qubitdyne/codex/fix-warnings-in-carbonyl-b…
nbritton Sep 29, 2025
e438b48
Scale SIXEL frames to terminal geometry
nbritton Sep 29, 2025
0cbd0c9
Merge pull request #8 from Qubitdyne/codex/fix-sixel-scaling-to-termi…
nbritton Sep 29, 2025
b134ceb
Fix sixel rendering resolution and palette issues
nbritton Sep 29, 2025
3194c34
Merge pull request #9 from Qubitdyne/codex/fix-sixel-rendering-issues…
nbritton Sep 29, 2025
5be51b1
Fix sixel diffusion method for new crate version
nbritton Sep 29, 2025
5efa3dc
Merge pull request #10 from Qubitdyne/codex/fix-diffusionmethod-varia…
nbritton Sep 29, 2025
b3b7118
Fix sixel dithering and enforce integer DSF
nbritton Sep 29, 2025
a78d22c
Merge pull request #11 from Qubitdyne/codex/fix-invalid-dithering-met…
nbritton Sep 29, 2025
a0e389c
Wire DSF and zoom through bridge
nbritton Sep 30, 2025
9d94dd7
Merge pull request #12 from Qubitdyne/codex/wire-dsf-through-to-chrom…
nbritton Sep 30, 2025
d8a4a69
Make bridge FFI optional at runtime
nbritton Sep 30, 2025
22a65a3
Merge pull request #13 from Qubitdyne/codex/fix-linking-issues-after-…
nbritton Sep 30, 2025
c318d87
Fix Chromium patch hunk lengths for zoom integration
nbritton Sep 30, 2025
7420c02
Merge pull request #14 from Qubitdyne/codex/fix-font-size-increase-issue
nbritton Sep 30, 2025
545d60b
Clean up git am state before applying patches
nbritton Sep 30, 2025
8cb02ac
Merge pull request #15 from Qubitdyne/codex/fix-font-size-in-ui
nbritton Sep 30, 2025
e334c32
Fix bridge component dependencies
nbritton Sep 30, 2025
07fd655
Merge pull request #16 from Qubitdyne/codex/fix-font-size-in-ui-wwxze2
nbritton Sep 30, 2025
cb9c682
Fix default zoom without zoom component
nbritton Sep 30, 2025
f475030
Merge pull request #17 from Qubitdyne/codex/increase-font-size-in-ui
nbritton Sep 30, 2025
6fc51f3
Decouple bridge state from content dependencies
nbritton Sep 30, 2025
192787f
Merge pull request #18 from Qubitdyne/codex/fix-font-size-adjustment-…
nbritton Sep 30, 2025
4206486
Remove legacy rendering modes
nbritton Sep 30, 2025
7e10f2b
Merge pull request #19 from Qubitdyne/codex/increase-font-size-and-re…
nbritton Sep 30, 2025
05324fc
Restore repository state to PR #11 (a78d22c)
nbritton Sep 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
897 changes: 868 additions & 29 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ libc = "0.2"
unicode-width = "0.1.10"
unicode-segmentation = "1.10.0"
chrono = "0.4.23"
sixel-bytes = "0.2"
fast_image_resize = { version = "5", features = ["rayon"] }

[lib]
name = "carbonyl"
Expand Down
20 changes: 16 additions & 4 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ fn link_sysroot() {
"cargo:rustc-link-arg=--sysroot=./chromium/src/build/linux/debian_bullseye_amd64-sysroot"
);
} else {
println!("cargo:warning={}", "x86_64 debian sysroot provided by chromium was not found!");
println!("cargo:warning={}", "carbonyl may fail to link against a proper libc!");
println!(
"cargo:warning={}",
"x86_64 debian sysroot provided by chromium was not found!"
);
println!(
"cargo:warning={}",
"carbonyl may fail to link against a proper libc!"
);
}
}

Expand All @@ -29,8 +35,14 @@ fn link_sysroot() {
"cargo:rustc-link-arg=--sysroot=./chromium/src/build/linux/debian_bullseye_i386-sysroot"
);
} else {
println!("cargo:warning={}", "x86 debian sysroot provided by chromium was not found!");
println!("cargo:warning={}", "carbonyl may fail to link against a proper libc!");
println!(
"cargo:warning={}",
"x86 debian sysroot provided by chromium was not found!"
);
println!(
"cargo:warning={}",
"carbonyl may fail to link against a proper libc!"
);
}
}

Expand Down
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ $ carbonyl https://github.com
</tbody>
</table>

## Rendering

Carbonyl now prefers Sixel graphics for page rendering whenever the terminal reports support. Legacy character-based rendering is automatically used as a fallback if Sixel frames cannot be sent. Sixel scrolling is enabled by default so web content can be browsed normally; set `CARBONYL_SIXEL_SCROLL=off` (or `0`) to opt back into the legacy non-scrolling behaviour.

## Known issues

- Fullscreen mode not supported yet
Expand Down
14 changes: 11 additions & 3 deletions src/browser/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,15 @@ pub extern "C" fn carbonyl_renderer_resize(bridge: RendererPtr) {
let mut bridge = bridge.unwrap().lock().unwrap();
let window = bridge.window.update();
let cells = window.cells.clone();
// Use the full terminal pixel geometry for SIXEL frames.
let geometry = window.graphics_px;

log::debug!("resizing renderer, terminal window: {:?}", window);

bridge
.renderer
.render(move |renderer| renderer.set_size(cells));
bridge.renderer.render(move |renderer| {
renderer.set_size(cells);
renderer.update_sixel_geometry(geometry);
});
}

#[no_mangle]
Expand Down Expand Up @@ -411,6 +414,11 @@ pub extern "C" fn carbonyl_renderer_listen(bridge: RendererPtr, delegate: *mut B
Terminal(terminal) => match terminal {
TerminalEvent::Name(name) => log::debug!("terminal name: {name}"),
TerminalEvent::TrueColorSupported => renderer.enable_true_color(),
TerminalEvent::SixelSupported { .. } => {
let geometry = bridge.lock().unwrap().window.graphics_px;

renderer.enable_sixel(geometry)
}
},
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ pub struct CommandLine {
pub zoom: f32,
pub debug: bool,
pub bitmap: bool,
pub sixel_only: bool,
pub program: CommandLineProgram,
pub shell_mode: bool,
}

pub enum EnvVar {
Debug,
Bitmap,
SixelOnly,
ShellMode,
}

Expand All @@ -24,6 +26,7 @@ impl EnvVar {
match self {
EnvVar::Debug => "CARBONYL_ENV_DEBUG",
EnvVar::Bitmap => "CARBONYL_ENV_BITMAP",
EnvVar::SixelOnly => "CARBONYL_ENV_SIXEL_ONLY",
EnvVar::ShellMode => "CARBONYL_ENV_SHELL_MODE",
}
}
Expand All @@ -41,6 +44,7 @@ impl CommandLine {
let mut zoom = 1.0;
let mut debug = false;
let mut bitmap = false;
let mut sixel_only = true;
let mut shell_mode = false;
let mut program = CommandLineProgram::Main;
let args = env::args().skip(1).collect::<Vec<String>>();
Expand Down Expand Up @@ -77,6 +81,12 @@ impl CommandLine {
"-z" | "--zoom" => set_f32!(zoom = zoom / 100.0),
"-d" | "--debug" => set!(debug, Debug),
"-b" | "--bitmap" => set!(bitmap, Bitmap),
"--sixel-only" => set!(sixel_only, SixelOnly),
"--legacy-text" => {
sixel_only = false;

env::set_var(EnvVar::SixelOnly, "0");
}

"-h" | "--help" => program = CommandLineProgram::Help,
"-v" | "--version" => program = CommandLineProgram::Version,
Expand All @@ -92,6 +102,14 @@ impl CommandLine {
bitmap = true;
}

if let Ok(value) = env::var(EnvVar::SixelOnly) {
let normalized = value.trim().to_ascii_lowercase();

sixel_only = !matches!(normalized.as_str(), "0" | "false" | "off" | "no");
}

env::set_var(EnvVar::SixelOnly, if sixel_only { "1" } else { "0" });

if env::var(EnvVar::ShellMode).is_ok() {
shell_mode = true;
}
Expand All @@ -102,6 +120,7 @@ impl CommandLine {
zoom,
debug,
bitmap,
sixel_only,
program,
shell_mode,
}
Expand Down
1 change: 1 addition & 0 deletions src/cli/usage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Usage: carbonyl [options] [url]
Options:
-f, --fps=<fps> set the maximum number of frames per second (default: 60)
-z, --zoom=<zoom> set the zoom level in percent (default: 100)
--legacy-text re-enable the legacy ANSI text renderer
-b, --bitmap render text as bitmaps
-d, --debug enable debug logs
-h, --help display this help message
Expand Down
1 change: 1 addition & 0 deletions src/input.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod dcs;
mod graphics;
mod keyboard;
mod listen;
mod mouse;
Expand Down
72 changes: 72 additions & 0 deletions src/input/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::control_flow;

use super::{Event, ParseControlFlow, TerminalEvent};

#[derive(Default, Clone, Debug)]
pub struct Graphics {
params: Vec<u32>,
buffer: Vec<u8>,
}

impl Graphics {
pub fn new() -> Self {
Self::default()
}

pub fn parse(&mut self, key: u8) -> ParseControlFlow {
match key {
b'0'..=b'9' => {
self.buffer.push(key);

control_flow!(continue)
}
b';' => {
self.push_param();

control_flow!(continue)
}
b'S' => {
self.push_param();

control_flow!(break self.event())?
}
_ => control_flow!(break)?,
}
}

fn push_param(&mut self) {
if self.buffer.is_empty() {
self.params.push(0);
return;
}

if let Ok(text) = std::str::from_utf8(&self.buffer) {
if let Ok(value) = text.parse::<u32>() {
self.params.push(value);
}
}

self.buffer.clear();
}

fn event(&mut self) -> Option<Event> {
let params = std::mem::take(&mut self.params);

if params.len() >= 2 {
let item = params[0];
let status = params[1];

if item == 2 && status == 0 {
let width = params.get(2).copied().unwrap_or_default();
let height = params.get(3).copied().unwrap_or_default();

return Some(Event::Terminal(TerminalEvent::SixelSupported {
width,
height,
}));
}
}

None
}
}
5 changes: 5 additions & 0 deletions src/input/parser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ops::ControlFlow;

use super::graphics::Graphics;
use crate::input::*;

#[derive(Default)]
Expand All @@ -17,12 +18,14 @@ enum Sequence {
Mouse(Mouse),
Keyboard(Keyboard),
DeviceControl(DeviceControl),
Graphics(Graphics),
}

#[derive(Clone, Debug)]
pub enum TerminalEvent {
Name(String),
TrueColorSupported,
SixelSupported { width: u32, height: u32 },
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -91,12 +94,14 @@ impl Parser {
},
Sequence::Control => match key {
b'<' => Sequence::Mouse(Mouse::new()),
b'?' => Sequence::Graphics(Graphics::new()),
b'1' => Sequence::Keyboard(Keyboard::new()),
key => emit!(Keyboard::key(key, 0)),
},
Sequence::Mouse(ref mut mouse) => parse!(mouse, key),
Sequence::Keyboard(ref mut keyboard) => parse!(keyboard, key),
Sequence::DeviceControl(ref mut dcs) => parse!(dcs, key),
Sequence::Graphics(ref mut graphics) => parse!(graphics, key),
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/input/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,16 @@ impl TTY {
write!(out, "\x1b[?{}{}", sequence, if enable { "h" } else { "l" })?;
}

// Set the current foreground color to black
// Set the current background color to black
write!(out, "\x1b[48;2;0;0;0m")?;
// Query current foreground color to for true-color support detection
write!(out, "\x1bP$qm\x1b\\")?;
// Query current terminal name
write!(out, "\x1bP+q544e\x1b\\")?;
// Query graphics capability (XTSMGRAPHICS). Some terminals expect DCS form;
// use it first and fall back to CSI if ignored.
write!(out, "\x1bP?2;1;0S\x1b\\")?;
write!(out, "\x1b[?2;1;0S")?;

out.flush()
}
Expand Down
1 change: 1 addition & 0 deletions src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod painter;
mod quad;
mod render_thread;
mod renderer;
mod sixel;
mod window;
mod xterm;

Expand Down
2 changes: 2 additions & 0 deletions src/output/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct Cell {
/// Text grapheme if any
pub grapheme: Option<Rc<Grapheme>>,
pub quadrant: (Color, Color, Color, Color),
pub image: bool,
}

impl Cell {
Expand All @@ -31,6 +32,7 @@ impl Cell {
Color::black(),
Color::black(),
),
image: false,
}
}
}
Loading