<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sujit Baruwal</title>
    <description>The latest articles on DEV Community by Sujit Baruwal (@itsmemyan).</description>
    <link>https://dev.to/itsmemyan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4166453%2Ff510d58a-19a1-4a2b-b268-7463569a0d6c.png</url>
      <title>DEV Community: Sujit Baruwal</title>
      <link>https://dev.to/itsmemyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/itsmemyan"/>
    <language>en</language>
    <item>
      <title>I wrote a Mac code editor in Rust with its own Metal UI toolkit</title>
      <dc:creator>Sujit Baruwal</dc:creator>
      <pubDate>Tue, 06 Oct 2026 13:10:45 +0000</pubDate>
      <link>https://dev.to/itsmemyan/i-wrote-a-mac-code-editor-in-rust-with-its-own-metal-ui-toolkit-2f72</link>
      <guid>https://dev.to/itsmemyan/i-wrote-a-mac-code-editor-in-rust-with-its-own-metal-ui-toolkit-2f72</guid>
      <description>&lt;p&gt;Every code editor I used daily was a web browser in a trench coat. VS Code,&lt;br&gt;
Zed's predecessors, all of them: Chromium or a web view somewhere in the stack,&lt;br&gt;
carrying the memory footprint and the uncanny almost-native feel. I wanted an&lt;br&gt;
editor that feels like it belongs on a Mac — native menus, native dialogs, the&lt;br&gt;
shortcuts my fingers already know — so I wrote one. In Rust. With its own GPU&lt;br&gt;
UI toolkit on Metal.&lt;/p&gt;

&lt;p&gt;It's called &lt;a href="https://github.com/sbaruwal/orbvane" rel="noopener noreferrer"&gt;Orbvane&lt;/a&gt;. It's open source&lt;br&gt;
(MIT/Apache-2.0), signed and notarized, and you can install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; sbaruwal/tap/orbvane
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This post is about the technical decisions that made it possible — and the ones&lt;br&gt;
that bit me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft4zfvg3lhielyqp2d9on.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft4zfvg3lhielyqp2d9on.png" alt="Orbvane in the Orbvane Night theme" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not Electron (or Tauri, or GPUI)
&lt;/h2&gt;

&lt;p&gt;The short version: control. A web view decides your memory floor, your input&lt;br&gt;
latency, and how "native" your app can ever feel. I wanted keystrokes that land&lt;br&gt;
in under a millisecond in a million-line file, 120Hz scrolling, and a UI that&lt;br&gt;
respects macOS conventions instead of approximating them.&lt;/p&gt;

&lt;p&gt;The longer version: I enjoy suffering, apparently. Writing your own UI toolkit&lt;br&gt;
means writing your own text layout, focus management, menus, dialogs, drag and&lt;br&gt;
drop — everything a platform or framework normally hands you. The bill comes&lt;br&gt;
due in the least glamorous places. More on that below.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;The stack, bottom to top:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windowing:&lt;/strong&gt; &lt;code&gt;winit&lt;/code&gt;. It handles the platform layer and, importantly, the
&lt;code&gt;NSTextInputClient&lt;/code&gt; bridging on macOS that makes input methods work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering:&lt;/strong&gt; &lt;code&gt;wgpu&lt;/code&gt; on Metal, with our own retained-mode UI toolkit on top.
Retained, not immediate-mode: the toolkit keeps a scene of what's on screen
and re-renders only what changed (dirty-rect tracking). Immediate mode is
lovely to write, but you re-pay the layout cost every frame. Caching
glyphs and layout in RAM is what makes 120Hz scroll possible — RAM usage
isn't the enemy, redoing work is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text:&lt;/strong&gt; &lt;code&gt;cosmic-text&lt;/code&gt; for shaping (it handles ligatures, complex scripts,
emoji), over our own buffer with rope-like structure for large files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Languages:&lt;/strong&gt; tree-sitter for highlighting (36 grammars), and real language
servers over LSP for everything smart — diagnostics, completion, rename,
go-to-definition. The editor doesn't reimplement what servers already do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging:&lt;/strong&gt; DAP. &lt;code&gt;lldb-dap&lt;/code&gt; for Rust/C/C++/Swift, &lt;code&gt;debugpy&lt;/code&gt; for Python,
Delve for Go, and our own adapter for Node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal:&lt;/strong&gt; our own xterm-compatible emulator with split panes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; the assistant talks to the CLIs you already have (&lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;codex&lt;/code&gt;)
instead of shipping another API integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The principle throughout: own the things that define the feel (rendering, text,&lt;br&gt;
input), rent the things that are protocols (LSP, DAP, MCP-shaped tools).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcjp1lxqh8638hvt58yl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcjp1lxqh8638hvt58yl.png" alt="Orbvane in the Orbvane Day theme" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that taught me the most
&lt;/h2&gt;

&lt;p&gt;Shortly after launch, someone asked on X how the custom GPU toolkit handles CJK&lt;br&gt;
IME input — "that's usually what breaks first in custom-drawn editors." They&lt;br&gt;
were right, and it was broken: winit was emitting the IME preedit/commit&lt;br&gt;
events, and nothing in the editor handled them. CJK composition simply didn't&lt;br&gt;
work.&lt;/p&gt;

&lt;p&gt;The fix shipped the same day in 0.3.2: handle the preedit events, render the&lt;br&gt;
marked text with an underline at the caret, position the candidate window at&lt;br&gt;
the caret, and give CJK/emoji their proper two-column width in the editor.&lt;/p&gt;

&lt;p&gt;The lesson generalizes: in a custom-drawn editor, &lt;strong&gt;text input is the feature&lt;/strong&gt;.&lt;br&gt;
Not rendering, not themes — input. IME, dead keys, bidirectional text,&lt;br&gt;
accessibility APIs. These are the unglamorous systems that decide whether your&lt;br&gt;
editor works for everyone or just for people who type ASCII. I now treat every&lt;br&gt;
one of them as load-bearing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's genuinely hard
&lt;/h2&gt;

&lt;p&gt;Honesty section. Things that are done, things that aren't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Done:&lt;/strong&gt; fast startup, huge files, LSP/DAP/terminal/git/tests/extensions,
AI assistant, IME with inline composition, no telemetry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not done:&lt;/strong&gt; accessibility (VoiceOver) — custom GPU UI is invisible to
assistive tech until you implement the macOS accessibility APIs, and that's
real work touching the whole UI tree. This is next on my list after input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Untested:&lt;/strong&gt; bidirectional text. Shaping handles it; caret movement in
mixed-direction text is where custom editors break, and I haven't verified
ours yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;By design, missing:&lt;/strong&gt; remote dev over SSH, notebooks, running extension
JavaScript. Some of these will come; some are deliberate scope cuts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it, break it, tell me
&lt;/h2&gt;

&lt;p&gt;Orbvane is at &lt;a href="https://github.com/sbaruwal/orbvane" rel="noopener noreferrer"&gt;github.com/sbaruwal/orbvane&lt;/a&gt;.&lt;br&gt;
Issues are open and I read all of them — the IME fix started as a reply on&lt;br&gt;
social media and shipped hours later. If you type CJK daily, if you live in&lt;br&gt;
&lt;code&gt;lldb&lt;/code&gt;, if you have opinions about retained vs. immediate mode rendering: I'd&lt;br&gt;
genuinely like your eyes on it.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>macos</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
