Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
12 commits
Select commit Hold shift + click to select a range
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
42 changes: 33 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Проверки на каждый пуш и PR: Rust (clippy, тесты) и интерфейс (синтаксис, импорты, словари).
# Проверки на каждый пуш и PR: Rust (clippy, тесты) и интерфейс (синтаксис, импорты, словари, тесты ядра).
name: CI

on:
Expand All @@ -20,8 +20,8 @@ concurrency:
cancel-in-progress: true

jobs:
check:
name: Checks
interface:
name: Interface
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
Expand All @@ -33,27 +33,51 @@ jobs:
node-version: 22
cache: npm

- name: Interface
- name: Syntax, imports, dictionaries, core tests
run: |
npm ci --no-audit --no-fund
npm run check
npm test

# На всех трёх системах: у каждой свой платформенный код (опрос Alt, окно, диалоги),
# и он должен компилироваться до релиза, а не впервые на теге.
rust:
name: Rust (${{ matrix.name }})
strategy:
fail-fast: false
matrix:
include:
- name: Linux
os: ubuntu-24.04
- name: Windows
os: windows-latest
- name: macOS
os: macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}

- name: Linux system libraries
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libwebkit2gtk-4.1-dev librsvg2-dev libayatana-appindicator3-dev patchelf \
pkg-config libclang-dev libxcb1-dev libxrandr-dev libdbus-1-dev \
libpipewire-0.3-dev libwayland-dev libegl-dev libgbm-dev
sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev librsvg2-dev libayatana-appindicator3-dev patchelf pkg-config libclang-dev libxcb1-dev libxrandr-dev libdbus-1-dev libpipewire-0.3-dev libwayland-dev libegl-dev libgbm-dev

- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
components: clippy, rustfmt

- uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri

- name: Format
if: runner.os == 'Linux'
working-directory: src-tauri
run: cargo fmt --check

- name: Clippy
working-directory: src-tauri
run: cargo clippy --all-targets --locked -- -D warnings
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Заметки — раздел версии из CHANGELOG.md; без раздела релиз не выпускаем.
awk -v v="${TAG#v}" 'index($0, "## [" v "]") == 1 { on = 1; next } on && /^## \[/ { exit } on' CHANGELOG.md > notes.md
test -s notes.md || { echo "В CHANGELOG.md нет раздела ## [${TAG#v}]"; exit 1; }
gh release view "$TAG" > /dev/null 2>&1 || gh release create "$TAG" --draft --verify-tag \
--title "Sketchover ${TAG#v}" \
--notes "Установщики: Windows — .exe, macOS — .dmg (Intel и Apple Silicon), Linux — .AppImage, .deb или .rpm."
--title "Sketchover ${TAG#v}" --notes-file notes.md
echo "id=$(gh release view "$TAG" --json databaseId -q .databaseId)" >> "$GITHUB_OUTPUT"

build:
Expand Down
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Changelog

All notable changes to Sketchover. The release workflow takes the notes for each version from this file.

## [0.1.0] — first release

Draw on your screen during calls — a free screen annotation tool for Windows, macOS and Linux.

### Drawing
- Brush, line, arrow, rectangle, ellipse, text, text blocks, laser pointer and eraser over every window.
- Text blocks and text with Markdown: headings, bullet and numbered lists that continue on `Enter`, **bold**, *italic*, `code`, ~~strikethrough~~. Double-click to edit with any tool.
- Arrows attach to text blocks and screenshots and follow them.
- Region screenshots (`S`): select part of the screen and it lands on the canvas — move, resize, rotate.

### Calls
- One global hotkey, `` Alt+` `` (configurable), opens the canvas on the monitor under the cursor.
- Hold `Alt` to click and scroll the windows below; double-tap `Alt` to stay in click-through mode (Windows, macOS).
- `Ctrl+Shift+C` copies the drawing as an image — paste it into the call chat.
- `Ctrl+S` saves a PNG that opens anywhere and keeps the editable canvas inside; `Ctrl+O` opens it again.

### App
- Starts with the system and waits in the tray; closing the canvas only hides it.
- Keys work on any keyboard layout: `1…0` tools, `Alt+1…8` colors, `Shift+1…3` stroke width, `F1` cheat sheet.
- Settings panel: language, hotkey, start with the system, updates, about.
- 11 languages: English, Русский, Deutsch, Español, Français, Português, 中文, 日本語, 한국어, العربية, हिन्दी.
- Signed automatic updates through ProAnima Hub.

### Install
- Windows 10/11 — `.exe`, no admin rights needed.
- macOS 11+ — one `.dmg` for Intel and Apple Silicon.
- Linux (Ubuntu 24.04+, Debian 13+, Fedora 40+) — AppImage, `.deb`, `.rpm`.

The installers are not yet signed with a paid developer certificate: on first launch Windows may show “Windows protected your PC” (More info → Run anyway), and macOS may ask you to open the app with right-click → Open.
15 changes: 8 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@
- **O**: новый инструмент добавляется новым модулем/записью в реестре инструментов, а не ещё одной веткой `if/switch` в общем коде.
- **L**: все инструменты имеют единый интерфейс (`down`, `move`, `up` + метаданные `id`, `label`, `icon`/`iconPath`); подменяемы без правок вызывающего кода. Рисуют фигуры не инструменты, а `ui/canvas.js`.
- **I**: модуль получает только то, что ему нужно (узкие аргументы/колбэки), а не весь `state`.
- **D**: логика зависит от маленьких интерфейсов, а не от Tauri/DOM напрямую. Доступ к ОС — только через `src/ui/api.js` (команды и события Tauri). Чистая логика (геометрия, история, фигуры) не трогает DOM и Tauri и тестируется отдельно.
- **D**: логика зависит от маленьких интерфейсов, а не от Tauri/DOM напрямую. Доступ к ОС — только через `src/ui/api.js` (команды и события Tauri). Чистая логика (геометрия, история, фигуры) не трогает DOM и Tauri и покрыта тестами (`tests/`, `node:test`, без зависимостей).

### Зависимости между слоями (строго вниз, без циклов)
```
src-tauri/ (Rust: окно, сквозные клики, трей, хоткей, настройки, снимок экрана, обновления) ←команды/события→ src/ui/api.js
src-tauri/ (Rust: окно, сквозные клики, трей, хоткей, настройки, снимок экрана, файлы и буфер, обновления) ←команды/события→ src/ui/api.js
src/ui/ холст, панель, настройки, ввод, режимы (верхний слой)
src/tools/ инструменты с единым интерфейсом down/move/up
src/core/ состояние, фигуры, геометрия, история, Markdown, картинки (чистая логика)
src/core/ состояние, фигуры, геометрия, история, Markdown, картинки, формат файла (чистая логика)
src/i18n/ словари; используется только из ui
```
- Инструмент получает от UI только `host = { render, edit }` — так `tools` не импортирует `ui`.
- Измерение текста подставляется в `core` через `setTextMeasurer` — `core` не знает про canvas.
- `core` не импортирует `tools`/`ui`; `tools` не импортирует `ui`. Циклических импортов нет.
- Общее состояние — в одном месте (`core/state.js`), мутации через явные функции.
- Rust-сторона ничего не знает о рисовании; интерфейс ничего не знает об окнах ОС.
- В Rust: один модуль — одна ответственность (`overlay`, `keys`, `hotkey`, `tray`, `settings`, `capture`, `updates`), команды — тонкие обёртки в `lib.rs`.
- В Rust: один модуль — одна ответственность (`overlay`, `keys`, `hotkey`, `tray`, `settings`, `capture`, `files`, `updates`), команды — тонкие обёртки в `lib.rs`.
- Окно трогаем только из главного потока: фоновые потоки лишь ставят задачи (`run_on_main_thread`) и не ждут их, замки не держат через вызовы окна — иначе взаимная блокировка.

## Безопасность (Tauri)
Expand All @@ -43,7 +43,8 @@ src/i18n/ словари; используется только из ui
- Строгий CSP в `tauri.conf.json` (`default-src 'self'`, без inline-скриптов и стилей). Стили из JS — только через CSSOM (`el.style.x = …`), не атрибутом.
- Не использовать `eval`, `new Function`, `innerHTML` с данными — только `textContent`/`createElement`.
- Сеть — только обновления через хаб (и запасной GitHub). Подпись каждого обновления проверяется ключом из конфига; приватный ключ — только в CI, никогда в репозитории.
- На диск пишем только настройки в каталоге конфигурации приложения (и запись автозапуска средствами системы); битые настройки → значения по умолчанию, не падение.
- На диск пишем только настройки в каталоге конфигурации приложения, запись автозапуска средствами системы и файлы, которые человек сам выбрал в системном диалоге (путь интерфейс не задаёт). Битые настройки → значения по умолчанию, не падение.
- Открываемые файлы — недоверенные: сцену проверяет `core/scene.js` (известные фигуры, корректные поля), размер файла ограничен.
- Ничего личного наружу: в хаб уходит только случайный `install_id`.
- Перед релизом: `cargo clippy -- -D warnings`, `npm audit`, актуальные Tauri и плагины.

Expand Down Expand Up @@ -71,7 +72,7 @@ src/i18n/ словари; используется только из ui
- Состояние режима (рисование / сквозные клики) всегда явно видно на экране.
- Панель не должна перекрывать работу и должна оставаться кликабельной в сквозном режиме.
- Настройки и «О программе» — одна компактная раскрываемая панель, не отдельные окна.
- Все тексты интерфейса — через `t(key)`, 11 языков как в Signal Lab; новый ключ добавляется во все словари. README.md — на английском (поиск), README.ru.md — полная русская версия, остальные документы — на русском; изменил поведение или горячую клавишу — обнови оба README.
- Все тексты интерфейса — через `t(key)`, 11 языков как в Signal Lab; новый ключ добавляется во все словари. README.md и CHANGELOG.md — на английском (поиск, страница релиза), README.ru.md — полная русская версия, остальные документы — на русском; новая версия — раздел в CHANGELOG.md (из него берутся заметки релиза); изменил поведение или горячую клавишу — обнови оба README.

## Стиль кода
- JS: ES-модули, `const` по умолчанию, `let` при необходимости, без `var`.
Expand All @@ -83,5 +84,5 @@ src/i18n/ словари; используется только из ui
## Git и процесс
- Коммиты небольшие и атомарные, формат `feat: ...`, `fix: ...`, `refactor: ...`, `docs: ...` (описание на русском, как в истории).
- Рефакторинг отдельно от изменения поведения.
- Перед коммитом: `npm run check`, `cargo fmt`, `cargo clippy --all-targets -- -D warnings` и `cargo test` чистые; `npm start` запускается, основные сценарии (рисование, сквозной режим, хоткей, настройки) проверены вручную. Это же гоняет CI.
- Перед коммитом: `npm run check`, `npm test`, `cargo fmt`, `cargo clippy --all-targets -- -D warnings` и `cargo test` чистые; `npm start` запускается, основные сценарии (рисование, сквозной режим, хоткей, настройки) проверены вручную. Это же гоняет CI.
- Основная ветка — `main`.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Sketchover puts a transparent canvas over every window. Press one hotkey on a Zo
- **Text blocks with Markdown**: headings, bullet and numbered lists (they continue on `Enter`), **bold**, *italic*, `code`, ~~strikethrough~~.
- **Arrows that stick**: arrows attach to text blocks and screenshots and follow them when you move them.
- **Region screenshots**: press `S`, select part of the screen, and it lands on the canvas — move it, resize it, rotate it.
- **Paste into the chat**: `Ctrl+Shift+C` copies your drawing as an image — paste it into Zoom, Teams, Slack or Telegram.
- **Save and keep editing**: `Ctrl+S` saves a PNG that opens anywhere and still contains the editable canvas — open it later with `Ctrl+O`.
- **Keyboard first, layout independent**: `1`…`0` pick tools, `Alt+1…8` colors, `Shift+1…3` stroke width, `F1` shows a cheat sheet.
- **Always ready, never in the way**: starts with your system and waits in the tray; one global hotkey (`` Alt+` ``, configurable) opens it on the monitor under your cursor.
- **Small and private**: a ~3 MB installer, no account, nothing leaves your computer except an anonymous update check.
Expand Down Expand Up @@ -61,6 +63,8 @@ Sketchover opens the canvas right after install, then lives in the tray (the men
| Region screenshot | `S` |
| Color / stroke width | `Alt+1…8` / `Shift+1…3` |
| Undo / redo | `Ctrl+Z` / `Ctrl+Y` |
| Copy the drawing as an image | `Ctrl+Shift+C` |
| Save / open (PNG with the editable canvas inside) | `Ctrl+S` / `Ctrl+O` |
| Delete selected / clear all | `Delete` / `Shift+Delete` |
| Edit a text block | double-click it with any tool |
| Cheat sheet | `F1` |
Expand All @@ -79,6 +83,8 @@ If you are looking for an **Epic Pen, ZoomIt, gInk, ppInk or Presentify alternat

**Does it collect data?** No account, no analytics in the canvas. The only network request is the update check, sent with a random install ID.

**How do I keep a drawing?** `Ctrl+S` saves a regular PNG — it opens in any image viewer — with the canvas embedded, so `Ctrl+O` brings it back fully editable. Or `Ctrl+Shift+C` and paste it straight into the chat.

**Is everything the same on Linux?** Almost: holding or double-tapping `Alt` is Windows and macOS only for now. On Linux, switch click-through with `Esc`, the mode button or the global hotkey.

## Build from source
Expand All @@ -90,9 +96,10 @@ npm install
npm start # run in development
npm run build # installer for the current system
npm run check # interface checks
npm test # core logic tests
```

Releases: `npm version patch && git push --follow-tags` — GitHub Actions builds the installers for all three systems into a draft release.
Releases: add a `## [X.Y.Z]` section to [CHANGELOG.md](CHANGELOG.md), then `npm version X.Y.Z && git push --follow-tags` — GitHub Actions builds the installers for all three systems into a draft release with those notes.

Tauri 2 (Rust) for the system side, plain JavaScript modules for the canvas, no bundler. Project rules: [CLAUDE.md](CLAUDE.md), roadmap: [docs/ROADMAP.md](docs/ROADMAP.md).

Expand Down
Loading
Loading