Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

πŸš€ NEO Emacs β€” A GPU-powered Emacs written in Rust with a modern display engine. Inline 4K images/4K videos/WPEWebKit using GPU acceleration, DMA-BUF, ZERO-COPY. Rich animation effects support. Aiming for modern design/multi-threaded Elisp, 10x performance and 100% Emacs compatibility.

License

Notifications You must be signed in to change notification settings

eval-exec/neomacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

1,752 Commits

Repository files navigation

I started Neomacs because I love Emacs, I respect Emacs, and I want to make it better. β€” Eval Exec

✨ "While other editors can save your files, only Emacs can save your soul." ✨

NEOMACS - The Future of Emacs

Status: Alpha Rust 1.92+ License: GPL-3.0

Note: Neomacs is in active alpha development. Expect rough edges, breaking changes, and missing features. Contributions and bug reports are very welcome!

Fork notice: Neomacs is a hard fork of GNU Emacs, forked from commit 705c0e3729. The changes are too invasive to ever be accepted upstream, so we did not preserve the original git history to keep the repository lightweight. If you need the full Emacs git history for reference, open an issue and we can re-add it.

Why a fork, not from scratch? Neomacs aims for 100% compatibility with official GNU Emacs β€” every config, package, and workflow should just work. By forking, we keep the original Emacs C code as a reference and test oracle: we can verify that each Rust rewrite produces identical behavior, ensuring nothing breaks as subsystems are replaced one by one.


The Problem

Emacs is a 40-year-old C codebase that hasn't kept up with modern hardware or software engineering:

  • Display engine β€” ~50,000 lines of C in xdisp.c, designed for text terminals in the 1980s. CPU-only rendering, no GPU acceleration, no native video/animations, no smooth visual effects
    • Large images β€” rendering slows down significantly
    • Video playback β€” not natively supported
    • Modern animations β€” no smooth cursor movement, buffer transitions, or visual effects
    • Web content β€” limited browser integration
    • GPU utilization β€” everything runs on CPU while your GPU sits idle
  • Elisp performance β€” no inline caching, stop-the-world GC, dynamic dispatch overhead. Even with native-comp (AOT), Elisp lacks runtime JIT optimization, speculative inlining, and concurrent GC β€” leaving significant performance on the table
  • Unsafe C codebase β€” ~300,000 lines of unsafe C with manual memory management, monolithic architecture (runtime and editor entangled), single-threaded design that prevents real concurrency

The Solution

Throw it all away and start fresh.

Neomacs is rewriting Emacs from the ground up in Rust β€” starting with the display engine and expanding to the core:

  • GPU display engine (done) β€” ~4,000 lines of Rust replacing ~50,000 lines of legacy C, powered by wgpu (Vulkan/Metal/DX12/OpenGL)
  • Rust layout engine (done) β€” bypasses xdisp.c entirely, reads buffer text via FFI and computes layout in Rust
  • Inline video/images/WebKit (done) β€” 4K video, GPU-decoded images, and WPE WebKit browser views embedded directly in buffers
  • 21 scroll effects, 8 cursor modes, 10 buffer transitions (done) β€” GPU-accelerated animations running on the render thread at display refresh rate
  • Zero-copy DMA-BUF (done) β€” efficient GPU texture sharing (Linux)
  • Rewrite entire Emacs core in Rust (in progress) β€” replacing all ~300,000 lines of C with safe, modern Rust: Elisp runtime, evaluator, bytecode VM, GC, buffer/window/frame subsystems, and all editor internals
  • True multi-threaded Elisp (planned) β€” real concurrency for the Lisp machine, not just cooperative threading
  • 10x Elisp performance (planned) β€” Rust-optimized Lisp machine with JIT compilation and inline caching
  • Full Emacs compatibility β€” your config and packages still work

Showcase

Animations (Cursor, Buffer Switch, Scroll)

2026εΉ΄02月07ζ—₯_16-49-54.mp4

GPU Text with Rounded Box Faces

Round corner box face attribute

Inline 4K Images

GPU-decoded directly β€” no CPU cost, won't block Emacs main thread.

Inline 4K images in Emacs buffer

Inline Web Browser (WPE WebKit)

GPU backend, DMA-BUF zero-copy.

Inline WPE WebKit browser in Emacs buffer

Inline Terminal (Alacritty)

GPU-backed terminal emulator embedded in Emacs buffer.

Inline Alacritty terminal in Emacs buffer

Inline 4K Video Playback

DMA-BUF zero-copy, GPU backend β€” no CPU cost.

2026εΉ΄02月07ζ—₯_16-36-47.mp4

Features

Working Now

Feature Description
GPU Text Rendering Hardware-accelerated text via wgpu (Vulkan/Metal/DX12/OpenGL)
Video Playback GStreamer + VA-API hardware decode with DMA-BUF zero-copy
Cursor Animations 8 modes with 7 movement styles and configurable spring trail
Scroll Animations 21 scroll effects with 5 easing functions
Buffer Transitions 10 buffer-switch effects (crossfade, slide, page-curl, etc.)
DMA-BUF Zero-Copy GPU-to-GPU texture sharing via Vulkan HAL (no CPU readback)
Inline Images GPU-accelerated image rendering in buffers
Inline WebKit WPE WebKit browser views embedded in buffers

Animations

All animations run on the GPU render thread at display refresh rate, independent of Emacs redisplay. Configure everything from Elisp.

Cursor

8 particle/visual modes (Neovide-inspired):

Mode Description
none No animation, instant movement
smooth Smooth interpolated movement (default)
railgun Particles shoot backward from cursor
torpedo Comet-like trail follows cursor
pixiedust Sparkly particles scatter around cursor
sonicboom Shockwave ring expands from cursor
ripple Concentric rings emanate outward
wireframe Animated outline glow

7 movement styles controlling how the cursor interpolates between positions:

Style Description
exponential Smooth deceleration, no fixed duration (uses speed param)
spring Critically-damped spring, Neovide-like feel (default)
ease-out-quad Gentle deceleration curve
ease-out-cubic Stronger deceleration curve
ease-out-expo Sharp deceleration curve
ease-in-out-cubic Smooth S-curve
linear Constant speed

The spring style also supports a 4-corner trail effect where leading corners snap ahead and trailing corners stretch behind, controlled by a trail-size parameter (0.0-1.0).

Buffer Switch (Crossfade/Transition)

10 buffer-switch effects triggered when the visible buffer changes:

Effect Description
none Instant switch
crossfade Alpha blend between old and new (default)
slide-left/right/up/down Directional slide transitions
scale-fade Scale and fade
push New buffer pushes old buffer out
blur Blur transition
page-curl 3D page-turning effect

Scroll

21 scroll animation effects organized into categories:

# Effect Category Description
0 slide 2D Content slides in scroll direction (default)
1 crossfade 2D Alpha blend between old and new positions
2 scale-zoom 2D Destination zooms from 95% to 100%
3 fade-edges 2D Lines fade at viewport edges
4 cascade 2D Lines drop in with stagger delay
5 parallax 2D Layers scroll at different speeds
6 tilt 3D Subtle 3D perspective tilt
7 page-curl 3D Page turning effect
8 card-flip 3D Card flips around X-axis
9 cylinder-roll 3D Content wraps around cylinder
10 wobbly Deformation Jelly-like deformation
11 wave Deformation Sine-wave distortion
12 per-line-spring Deformation Each line springs independently
13 liquid Deformation Noise-based fluid distortion
14 motion-blur Post-process Vertical blur during scroll
15 chromatic-aberration Post-process RGB channel separation
16 ghost-trails Post-process Semi-transparent afterimages
17 color-temperature Post-process Warm/cool tint by direction
18 crt-scanlines Post-process Retro scanline overlay
19 depth-of-field Post-process Center sharp, edges dim
20 typewriter-reveal Creative Lines appear left-to-right

5 scroll easing functions:

# Easing Description
0 ease-out-quad Standard deceleration (default)
1 ease-out-cubic Stronger deceleration
2 spring Critically damped spring with overshoot
3 linear Constant speed
4 ease-in-out-cubic Smooth S-curve

Configuration

;; All-in-one configuration:
;; (neomacs-set-animation-config
;; CURSOR-ENABLED CURSOR-SPEED CURSOR-STYLE CURSOR-DURATION
;; CROSSFADE-ENABLED CROSSFADE-DURATION
;; SCROLL-ENABLED SCROLL-DURATION
;; &optional SCROLL-EFFECT SCROLL-EASING TRAIL-SIZE)
;; Example: spring cursor, crossfade buffer switch, page-curl scroll with spring easing
(neomacs-set-animation-config t 15.0 'spring 150 t 200 t 150 7 2 0.7)
;; Example: fast linear cursor, no crossfade, wobbly scroll
(neomacs-set-animation-config t 20.0 'linear 100 nil 200 t 200 10 0 0.0)

The Ambitious Vision

Neomacs aims to be the most capable and beautiful Emacs ever built, rewriting its internals in Rust:

  • Rich media β€” 4K video, PDF rendering, image manipulation directly in buffers
  • GPU-native β€” hardware-accelerated rendering, shader effects, 120fps animations
  • GPU terminal β€” Rust-based terminal emulator replacing slow term.el/ansi-term/vterm
  • Cross-platform β€” Linux (Vulkan), macOS (Metal), Windows (Vulkan/DX12)
  • Rust core β€” rewrite Emacs C internals in Rust for memory safety and performance
  • Multi-threaded Elisp β€” true concurrency for the Lisp machine, enabling parallel Elisp execution
  • 10x faster Elisp β€” Rust-optimized Lisp interpreter/compiler to dramatically speed up Elisp

The goal: Make Emacs as powerful and beautiful as it deserves to be.


Architecture

Neomacs is rewriting Emacs from C to Rust with clean module boundaries. The goal is a layered architecture where the Elisp runtime is a self-contained core, editor subsystems are independent modules communicating through defined APIs, and the rendering engine runs on a separate GPU thread.

Current State

The rendering engine and layout engine are already in Rust. The Emacs C core still runs the Elisp evaluator, GC, and editor subsystems β€” connected to Rust via FFI channels.

Target Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Neomacs (Rust) β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Elisp Runtime Core β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ Evaluator β”‚ β”‚ Bytecode VM β”‚ β”‚ GC/Allocatorβ”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ LispObject β”‚ β”‚Symbol Table β”‚ β”‚ Type System β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Runtime API β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚register_typeβ”‚ β”‚register_rootβ”‚ β”‚define_func β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ run_hook β”‚ β”‚ specbind β”‚ β”‚signal_error β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Editor Modules β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚ β”‚ β”‚ Buffer β”‚ β”‚ Window β”‚ β”‚ Frame β”‚ β”‚Keyboardβ”‚ β”‚Processβ”‚β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚ β”‚ β”‚ Font β”‚ β”‚ Image β”‚ β”‚File IO β”‚ β”‚ Reader β”‚ β”‚ Data β”‚β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Rendering Engine β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚Layout Engineβ”‚ β”‚wgpu Rendererβ”‚ β”‚ Animations β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ winit β”‚ β”‚ WebKit β”‚ β”‚ GStreamer β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Threading β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚EmacsThread β”‚ β”‚RenderThreadβ”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ ▲さんかく β”‚ β”‚
β”‚ β”‚ β”œβ”€β”€ FrameGlyphBuffer (crossbeam) β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ └── InputEvent (crossbeam) ────────────────────┐ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Backends β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ Vulkan β”‚ β”‚ Metal β”‚ β”‚ DX12/GL β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Design principles:

  • Elisp Runtime Core is a self-contained Rust crate. It owns LispObject, the evaluator, bytecode VM, GC, specpdl, and symbol table. It does NOT know about buffers, windows, frames, or any editor concept.
  • Runtime API is a trait-based interface. Editor modules register their types (with GC trace descriptors), roots, and primitives. The GC traces registered types generically β€” no hardcoded mark_kboards() or mark_terminals().
  • Editor Modules are independent. Each owns its data structures and exposes them to Lisp through the Runtime API. Modules do not reach into each other's internals.
  • Rendering Engine runs on a separate GPU thread, communicating via crossbeam channels (FrameGlyphBuffer down, InputEvent up). Already implemented.

Why Rust?

  • Memory safety without garbage collection
  • Zero-cost abstractions for high-performance rendering
  • Excellent FFI with C (Emacs core)
  • Modern tooling (Cargo, async, traits)
  • Growing ecosystem for graphics (wgpu, winit, cosmic-text)

Why wgpu?

  • Cross-platform β€” single API for Vulkan, Metal, DX12, and OpenGL
  • Safe Rust API β€” no unsafe Vulkan/Metal code in application
  • WebGPU standard β€” future-proof API design
  • Active development β€” used by Firefox, Bevy, and many others

For an in-depth analysis of the current Emacs C architecture, why it's hard to rewrite, and why Elisp is slow, see docs/elisp-core-analysis.md.


Building

Prerequisites

  • Emacs source (this is a fork)
  • Rust (stable, 1.92+)
  • GStreamer (for video playback)
  • VA-API (optional, for hardware video decode on Linux)

Linux (Arch Linux)

# Install dependencies
sudo pacman -S --needed \
 base-devel autoconf automake texinfo clang git pkg-config \
 gtk4 glib2 cairo \
 gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad \
 wpewebkit wpebackend-fdo \
 wayland wayland-protocols \
 mesa libva \
 libjpeg-turbo libtiff giflib libpng librsvg libwebp \
 ncurses gnutls libxml2 sqlite jansson tree-sitter \
 gmp acl libxpm \
 libgccjit
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build the Rust display engine
cargo build --release --manifest-path rust/neomacs-display/Cargo.toml
# Build Emacs
./autogen.sh
./configure --with-neomacs --with-neovm-core-backend=emacs-c
make -j$(nproc)

Note: WPE WebKit (wpewebkit) is required for browser embedding. It is available in Arch Linux repos and via NixOS. On distros without WPE WebKit packages, the build will skip webkit support and build the Rust crate with --no-default-features --features "winit-backend,video".

Docker (Build Test)

docker build -t neomacs-build-test .

Uses Arch Linux. See the Dockerfile for the full build environment.

NixOS / Nix

Neomacs uses nix-wpe-webkit for the WPE WebKit dependency. Pre-built binaries are available via Cachix (~60MB download instead of ~1 hour build).

The flake.nix includes nixConfig for the Cachix cache. Pass --accept-flake-config to use it automatically, or configure it system-wide:

NixOS β€” add to your configuration (e.g., /etc/nixos/configuration.nix):

{
 nix.settings.substituters = [ "https://nix-wpe-webkit.cachix.org" ];
 nix.settings.trusted-public-keys = [ "nix-wpe-webkit.cachix.org-1:ItCjHkz1Y5QcwqI9cTGNWHzcox4EqcXqKvOygxpwYHE=" ];
}

Non-NixOS β€” add to ~/.config/nix/nix.conf:

extra-substituters = https://nix-wpe-webkit.cachix.org
extra-trusted-public-keys = nix-wpe-webkit.cachix.org-1:ItCjHkz1Y5QcwqI9cTGNWHzcox4EqcXqKvOygxpwYHE=

Build with Nix

Option 1 β€” Trust the nixConfig in flake.nix (simplest):

nix build --accept-flake-config
# Or enter development shell
nix develop --accept-flake-config

Option 2 β€” Pass Cachix flags directly:

nix build \
 --extra-substituters "https://nix-wpe-webkit.cachix.org" \
 --extra-trusted-public-keys "nix-wpe-webkit.cachix.org-1:ItCjHkz1Y5QcwqI9cTGNWHzcox4EqcXqKvOygxpwYHE="

Note: Both options require your user to be in trusted-users in /etc/nix/nix.conf (e.g., trusted-users = root @wheel your-username), or configure the cache system-wide as shown above.

Legacy (non-flake users):

nix-shell

Manual build (inside dev shell)

cargo build --release --manifest-path rust/neomacs-display/Cargo.toml
./autogen.sh
./configure --with-neomacs --with-neovm-core-backend=emacs-c
make -j$(nproc)

Core Backend Switch

Use --with-neovm-core-backend= to select which core backend gets compiled:

  • emacs-c (default): current stable path, uses Emacs C core.
  • rust: enables the Rust-core compile-time mode for NeoVM integration work.

Roadmap: Rust Display Engine Rewrite

We are rewriting the Emacs display engine entirely in Rust. The current system extracts glyphs from Emacs's C glyph matrices and sends them to the GPU β€” the next step is replacing the C layout engine (xdisp.c, dispnew.c, ~40k LOC) with a Rust layout engine that reads buffer data directly and produces GPU-ready glyph batches. One layout engine, two renderers: wgpu (GPU) and TUI (terminal).

See docs/rust-display-engine.md for the full design document.

Phase Scope Difficulty Enables
-1: Direct glyph hook ~2000 Medium Proves architecture, low risk
0: Snapshot infra ~1000 C, ~500 Rust Medium-Hard Foundation
1: Monospace ASCII layout ~2500 Rust Medium Basic editing
1.5: TUI renderer ~1200 Rust Medium Terminal Emacs
2: Face resolution ~1500 Rust Medium-Hard Syntax highlighting
3: Display properties ~5000 Rust Very hard Packages (company, which-key, org)
4: Mode-line & header-line ~1000 Rust Medium Status display
5: Variable-width & compositions ~1200 Rust Medium Proportional fonts, ligatures
6: Bidi ~3000 Rust Very hard International text
7: Images & media ~400 Rust Easy Already working

Total: ~17-18k LOC Rust replacing ~40k LOC C β€” fewer lines because we skip terminal/X11/GTK backend code, skip incremental matrix diffing (GPU redraws everything), and leverage modern Rust crates (cosmic-text, unicode-bidi) for the hard Unicode/shaping problems.


Contributing

Contributions welcome! Areas where help is needed:

  • Graphics programmers β€” shader effects, rendering optimizations
  • Rust developers β€” architecture, performance, safety
  • Emacs hackers β€” Lisp API design, integration testing
  • Documentation β€” tutorials, API docs, examples

Acknowledgments

Built with:

  • wgpu β€” Cross-platform GPU rendering (Vulkan/Metal/DX12/GL)
  • winit β€” Cross-platform window management
  • cosmic-text β€” Pure Rust text shaping
  • GStreamer β€” Video playback with VA-API
  • ash β€” Vulkan bindings for DMA-BUF import
  • Inspired by Neovide cursor animations

License

GNU General Public License v3.0 (same as Emacs)

About

πŸš€ NEO Emacs β€” A GPU-powered Emacs written in Rust with a modern display engine. Inline 4K images/4K videos/WPEWebKit using GPU acceleration, DMA-BUF, ZERO-COPY. Rich animation effects support. Aiming for modern design/multi-threaded Elisp, 10x performance and 100% Emacs compatibility.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /