Я учел фидбек сообщества, открыл исходный код и сменил стек — теперь на Rust написано 99,6% всего кода, а от Tauri и Webview я полностью отказался. В статье расскажу, что внедрено и улучшено, а также какие проблемы возникли в процессе рефакторинга.
С прошлой частью, где подробно описан функционал, можно ознакомиться здесь.

Ссылка на репозиторий проекта и последние релизы.
Первые версии Aquilum были на Tauri: логика на Rust, а интерфейс — веб-страница в системном WebView. Из-за этого сложно было контролировать потребление ОЗУ, и иногда приложение с открытой заметкой и графом занимало около больше 150 МБ. В прошлой статье я написал про 9 МБ — это был замер без WebView, и в комментах меня справедливо упрекнули.
В версии 0.3.0 WebView убран: весь интерфейс теперь на Rust. Переписывание заняло 4–5 дней, помогали Claude Opus 5.5 и Gemini 3.8 Flash.
Что за проект за такой?
Aquilum — локальная база знаний из обычных markdown-файлов, в которой все данные принадлежат только пользователю и не привязывают его к приложению. Каждая функция хранится в заметке в виде MarkDown, поэтому ваша база знаний будет полностью портативной!
Основные библиотеки проекта
Окно — winit, виджеты — Masonry, текст — parley, растеризация — vello_cpu, поиск — tantivy, база — SQLite, PDF — krilla.
Почему растеризация на CPU, а не GPU
Честно говоря, мне хотелось попробовать именно программную растеризацию, так как заметкам видеокарта почти не нужна.
Драйвер AMD занимал около 85 МБ оперативы — больше, чем всё приложение без него. Поэтому кадр рисует процессор, а на Windows его выводит WARP — программная реализация Direct3D от Microsoft, которой драйвер не нужен. На Mac и Linux кадр выводит Softbuffer.
Плавность скролла
Больше всего времени я потратил на плавность прокрутки, и каждое изменение начиналось с замера. Колесо — порт кривой Безье из Firefox, тачпад — DirectManipulation со своей инерцией.
Окончательно плавным я его сделал совсем недавно после сотен попыток! Только тяжелые бенчмарки помогают находить узкие горлышки и справлять их — с помощью них я, в основном, и улучшаю производительность. Моя функция сводится к тому, чтобы придумывать тяжелые условия для испытания приложения, а агент уже пишет код и гоняет эти тесты.
Почему пришлось форкать движки
В выпущенной Masonry нет рендера на процессоре, поэтому взята основная ветка, и из неё только ядро masonry_core: готовый хост окна умеет работать только с видеокартой. Так как цель — рендеринг на процессоре, то пришлось дописывать библиотеку с помощью моих нейронных друзей.
Также Masonry перерисовывает всё окно на каждом кадре: при вводе это около 14 мс задержки, поэтому библиотеку пришлось кардинально оптимизировать и перерисовывать только изменившиеся области при скролле и взаимодействии с интерфейсом.
Вместе с работой над циклом кадра это подняло прокрутку тяжёлой заметки с 10 до 115–120 кадров в секунду, а удаление символа в большой заметке ускорилось с 81 до 1 мс (заметка 141 КБ, масштаб 175 %, 120 Гц, Ryzen 9 8945HS).
Перерисовка только измененных областей
Для каждой команды рисования считается отпечаток и её прямоугольник на экране. Сравнение с прошлым кадром даёт до четырёх изменившихся прямоугольников: только они растрируются и только они уходят в окно.
Мигание каретки перерисовывает только её место. Строка текста сравнивается кусками по 48 пикселей, поэтому раскрытие разметки рядом с кареткой не перерисовывает всю строку (так же сделано в Chromium и Firefox).
Уже нарисованные пиксели сдвигаются копированием, растрируется только открывшаяся полоса. Края областей округляются до целых пикселей экрана, иначе при масштабе 175 % сдвиг не срабатывал.
Чтобы видеть, что именно перерисовывается, сделана подсветка перерисовки (paint flashing, как в Chrome DevTools). С ней я находил и недорисованные области, и избыточную перерисовку.
Например, раньше при скролле перерисовывалась вся ширина редактора, а после внедрения подсветки только контентная часть.

Красным вспыхивают области, которые растеризатор перерисовал в этом кадре.
Рамки: зелёная — область прокрутки, синяя — сдвиг пикселей при прокрутке, жёлтая — слой анимированной обложки, голубая — ползунок полосы прокрутки, который накладывается на готовый кадр без перерисовки страницы.
Свой редактор
Стандартное поле TextArea из Masonry на каждую букву заново раскладывает весь текст — около 15 мс на заметке в 141 КБ. А на огромных документах это время возрастает на порядок, поэтому нужно было сделать систему, которая будет обновлять только ту строку, которую изменяет пользователь. В итоге текст раскладывается по абзацам через parley, разбор Markdown общий с ядром.

В итоге удалось добиться отклика при печати равного менее чем 1 мс на заметке весом 198Мб! Обсидиан такую даже не запустил :)
Работа с памятью
Цель — 50–60 МБ частной памяти: без этого приложение не выпускалось.

Что дало больше всего:
Картинки держатся в оперативе, пока видны — как в Chromium. Без этого после закрытия всех вкладок в памяти оставалось около 80 МБ пикселей, теперь ноль. Так как в проекте нет React, то и все эти сбросы кэшей пришлось писать с нуля и тщательно тестировать...
Картинки декодируются сразу в нужном размере, чтобы не хранились в памяти в исходном разрешении. Эта фишка также работает во всех браузерах, но писать ее пришлось с нуля.
При сворачивании окна все лишние процессы очищаются — приложение в простое почти ничего не потребляет, что также важно при работе на ноутбуках, иначе тратится батарейка.
Вывод через WARP вместо драйвера видеокарты — минус около 85 МБ.
Также огромный прирост дают бенчмарки — я открывал, например, заметку на 196Мб в редакторе и сравнивал с аналогами стабильность работы. Obsidian вообще ее не открыл, а в заметочнике моего коллеги все работало без проблем. У меня же тормозил скролл и потребление памяти достигало монструозных 2.2Гб оперативы. Я замерял, на что уходят ресурсы, искал решения, обсуждал их с агентом и пробовал применять. В итоге заметка на 196Мб на данный момент занимает 225Мб оперативной памяти.
Свои читалка, граф, PDF и видеоплеер
Читалка открывает EPUB, FB2, MOBI и AZW3 без браузера: книга распаковывается, разбирается и раскладывается на страницы внутри приложения.

Граф раскладывает ядро, а рисует окно своим растеризатором: картинка делится на полосы, и полосы рисуются параллельно на всех ядрах процессора. Если, пока граф двигается, кадр выходит дольше 12 мс, граф временно рисуется в половинном разрешении.

PDF при экспорте раньше печатал браузер: на macOS без установленного принтера получался пустой лист, на Linux открывалось окно печати. Теперь PDF записывается напрямую через библиотеку krilla: текст векторный и выделяется, принтер и браузер не нужны ни на одной ОС.
Видео играет через системные средства: Media Foundation и WASAPI на Windows, AVFoundation на macOS, GStreamer на Linux. На Linux программе нужны только GStreamer, GLib, fontconfig и FreeType, а ещё X11 или Wayland, которые есть в любой системе. GTK и WebKitGTK больше не нужны.
Заключение
Спасибо огромное всем тем, кто подсказал, куда можно двигаться проекту и оставлял пул реквесты с исправлениями — почти все их я уже включил в последнюю версию Aquilum!
Отдельное спасибо Павлу, с которым мы ежедневно тестируем новые сборки и оптимизируем проект! Ежедневно я получаю от него новые баги и узкие горлышки, которые стараюсь оперативно устранять)
Предложить новую механику можно мне в личку в телеграм, но лучше делать это через pul requests или issues в репозитории.
В этой статье не затронуты аспекты UI и UX, которых было не меньше, чем технических нововведений, поэтому им будет отведена отдельная статья.