diff --git a/CHANGELOG.md b/CHANGELOG.md
index e89d4c3..20e24aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,33 @@
# Changelog
+## 1.3.0
+
+The release where both windows became native and the installer started
+saying something.
+
+- **The Windows window is WinUI 3, and it is the one that gets installed.**
+ Until now the installer carried the Tk window, so installing MThread Draw on
+ Windows got the old interface, slowly, and the native one was only in a zip
+ nobody had a reason to open. The Tk window is gone: `mthread_draw/app.py`,
+ the `gui` extra and the customtkinter dependency with it. Linux keeps the
+ command line and the library.
+- **A macOS window, in SwiftUI.** Frosted glass over `NSVisualEffectView` with
+ behind-window blending, the same phone view with drag placement and the same
+ eraser, driving the same engine over a pipe. `tools/build_macos.py`
+ assembles the bundle around `swift build` and makes the disk image.
+- **The installer has a user interface.** Without one an MSI shows "gathering
+ required information", installs, and closes without a word, so a successful
+ install cannot be told apart from a failed one - and it was read as failure.
+ Now: welcome, where to put it, progress, finished, and a ticked offer to
+ start the program. Apps & features shows the install folder, and a new
+ version replaces the old one instead of sitting beside it.
+- **Builds happen outside the checkout.** This tree lives in OneDrive on one
+ machine, and a sync client holds handles on files while it uploads them.
+ Writing several thousand of them into a synced folder failed at a different
+ step every time, always with an access denied that named a file rather than
+ the cause. Everything is staged in temp; only the finished installer and zip
+ are copied into `dist/`.
+
## 1.2.0
The release that made the window an editor rather than a loader.
diff --git a/README.md b/README.md
index 917fda3..858a37a 100644
--- a/README.md
+++ b/README.md
@@ -4,73 +4,60 @@
-The drawing above draws itself, and it is not an illustration: those are the 232 strokes
-tools/make_hero.py gets out of examples/motorcycle.jpg, in the order the program sends them to a phone.
+Not an illustration — 232 real strokes from examples/motorcycle.jpg, in the order they are sent to the phone.
-
-
-
+
+
+
+
-
-
-### It draws pictures on an Android screen by touching it,
and it records and replays gestures. Nothing is installed on the phone.
+### Draws any picture on an Android screen by touching it.
Records and replays gestures. Nothing installed on the phone.
-USB or wireless ADB · no root on most devices · no Android SDK · one download, everything inside
+USB or wireless ADB · no root on most devices · no Android SDK · Python, OpenCV and adb travel inside the app
-
+
-A photograph in, 57 strokes and 478 touch points out — the exact path list sent to the device.
-On a Pixel 8 Pro that draws in under two seconds.
+57 strokes, 478 points — the exact path list sent to the device. Under two seconds on a Pixel 8 Pro.
----
+## Start
-## In about a minute
-
-| | |
+| | |
|---|---|
-| **1 · Install** | [**Windows**](https://github.com/MAXAWER/MThread-Draw/releases/latest) — `MThreadDraw-x.y.z-x64.msi`, Start Menu entry and uninstaller included. [**macOS**](https://github.com/MAXAWER/MThread-Draw/releases/latest) — `.dmg` for Apple Silicon or Intel, drag it to Applications. **Linux** — the command line, [from source](#from-source). |
-| **2 · Wake the phone** | Settings → About phone → tap **Build number** seven times → Developer options → **USB debugging**. Plug it in, or `adb connect 192.168.1.42:5555`. |
-| **3 · Draw** | It finds the phone, shows the screen live, and lays the drawing over exactly where it will land. Drag to move, wheel to resize, Shift and wheel to turn — then **START DRAWING**. |
-
-**Nothing else to install.** Python, OpenCV and **adb** all travel inside the
-application. Both windows are native — **WinUI 3** on Windows, **SwiftUI** on
-macOS — and each drives the same engine over a pipe, so neither has its own idea
-of how anything works. The builds are not signed: SmartScreen says "unknown
-publisher" once, and macOS wants a right-click → **Open** the first time.
+| **1** | Install: [Windows `.msi`](https://github.com/MAXAWER/MThread-Draw/releases/latest) · [macOS `.dmg`](https://github.com/MAXAWER/MThread-Draw/releases/latest) · Linux — [from source](#from-source). Unsigned, so Windows says "unknown publisher" once and macOS wants right-click → **Open**. |
+| **2** | On the phone: Settings → About phone → **Build number** ×7 → Developer options → **USB debugging**. Plug in, or `adb connect 192.168.1.42:5555`. |
+| **3** | Open it. Drag the drawing over the live screen, wheel to resize, Shift+wheel to turn — **START DRAWING**. |
----
+## What it does
-## What the window lets you do
-
-| | |
+| | |
|---|---|
-| **Place it exactly** | Drag the drawing across the live view; wheel resizes, Shift and wheel turns, `Flip` mirrors, `Fit` starts over. Held in fractions of the screen, so it survives the phone being turned. |
-| **Layers** | Several pictures arranged against each other, each with its own placement and its own tracer settings. Hide one, reorder them, remove one. |
-| **Erase single strokes** | Drag across the lines you do not want with the eraser on; `Undo erase` brings them back. |
-| **Re-trace in place** | The detail slider re-traces what is already loaded. No need to open the file again. |
-| **Record and replay** | Press record, do something on the phone, press stop. The file holds fractions of the screen, so it **replays on a different phone**, at any speed, any number of times. |
-| **No live view?** | If capture fails, a screenshot you copied off the phone by hand will do: it does not update, but its proportions are what placement needs. |
-
-Nothing to prepare, from the command line or from code:
+| **Place it by hand** | Drag, resize, turn, flip, `Fit`. Held in fractions of the screen, so it survives the phone being turned. |
+| **Layers** | Several pictures at once, each with its own placement and tracer settings. |
+| **Erase strokes** | Drag across the lines you do not want; `Undo erase` brings them back. |
+| **Re-trace in place** | The detail slider re-traces what is loaded — no reopening the file. |
+| **Record and replay** | The file holds fractions of the screen, so it **replays on a different phone**, at any speed. |
+| **Two tracers** | Canny for machines and buildings, flow-based coherent lines for faces and animals. The app asks what is in the picture, not which algorithm. |
+| **Native windows** | WinUI 3 on Windows, SwiftUI on macOS, both driving one shared engine. |
+| **No live view?** | A screenshot copied off the phone by hand will do — its proportions are what placement needs. |
```bash
mthread shape heart # a heart, fitted to the screen
-mthread text "hello" --y 0.35 # words, in any font this machine has
+mthread text "hello" --y 0.35 # any font this machine has
mthread record -o login.json # then: mthread play login.json --speed 2
```
@@ -79,108 +66,24 @@ from mthread import Device
Device().draw_paths([[(100, 200), (400, 200), (400, 600)]])
```
----
-
-## How a photograph becomes touches
-
-

-
-
-A tracer decides where the lines are, the result is thinned to one pixel wide,
-and each line is walked into a single stroke — not an outline *around* the line,
-which is what draws everything twice. Above is `examples/guitar.jpg`, untouched:
-57 strokes, 478 points.
+
-The app asks what is in the picture rather than which algorithm you would like:
-
-| What you say is in it | What runs | Why that one |
-|---|---|---|
-| **Buildings, machines, objects** | Canny edges, thinned, walked into strokes | Keeps every bit of structure an edge detector sees — which is what a machine or a building is made of. |
-| **Portraits, animals, nature** | Flow-based coherent lines, after Kang, Lee and Chui | Works out the direction each line runs in and filters along it: calmer, longer strokes, and a face stays a face. |
-
-Neither wins everywhere, which is why both are here. Colour is what gets lost —
-a finger draws one black line, so the output is always a line drawing.
-
-
-

-
-
Nothing prepared, retouched or masked — the files in examples/, resized and otherwise untouched.
-The only thing that differs between the columns is the two sliders every user has.
+
The files in examples/, resized and otherwise untouched — nothing prepared, retouched or masked.
----
-
-## Why it exists
-
-`adb shell input tap` spawns a process on the device for every call. At
-100–300 ms each, anything continuous — a gesture, a line, a test script — is
-unusably slow. `mthread` gets the whole drawing onto the device in one go
-instead: kernel events through a single pushed script where the phone allows it,
-and a 3 KB injector run through `app_process` where it does not. A stroke that
-takes 40 seconds through `input swipe` finishes in well under a second.
-
-Two pieces, and either works without the other: **`mthread`**, a Python library
-for synthetic touch input whose core has no dependencies at all, and **MThread
-Draw**, the desktop application on top of it.
-
-**[How it works, in detail →](docs/INTERNALS.md)** — the digitizer's own
-coordinate space, the three ways into a device and why a recent Pixel refuses
-the fast one, what "instant" costs, and how it draws like a hand.
-
----
-
-## What it works with
-
-| | |
-|---|---|
-| **Devices** | Anything `adb devices` lists, over USB or wireless ADB. Root is not needed on most devices. |
-| **Emulators** | Android Studio AVD, BlueStacks (`:5555`), LDPlayer (`:5555`), Nox (`:62001`), MEmu (`:21503`). Raw `/dev/input` support differs between builds — `mthread info` says which path yours gets, and [device reports](https://github.com/MAXAWER/MThread-Draw/issues/new?template=device_report.md) are welcome. |
-| **Images** | PNG, JPEG, BMP, WebP. Raster only for now. |
-| **Host** | Windows, macOS, Linux. Python 3.9+. |
-
-Used for drawing games and canvases, signatures and stamps, QA passes that
-replay a recorded flow against every build, and repetitive tapping in apps with
-no other automation hook. Whether automating a particular game is allowed is
-between you and that game's rules; this is a general-purpose input tool.
-
-
-
-From source, and building the applications yourself
-
-
-
-[`run.bat`](run.bat) on Windows and [`run.sh`](run.sh) elsewhere do the whole
-thing: virtual environment, dependencies, and `adb` if the machine has none.
-Otherwise:
-
-```bash
-git clone https://github.com/MAXAWER/MThread-Draw.git
-cd MThread-Draw
-
-pip install -e . # library only - no dependencies at all
-pip install -e ".[draw]" # + image tracing (OpenCV, NumPy, Pillow)
-pip install -e ".[bg]" # + rembg background removal
-```
+## Why it is fast
-`adb` is found in this order: `ADB_PATH`, the copy inside a packaged build, your
-`PATH`, a `platform-tools` directory beside the working directory, then the usual
-Android SDK locations. If you have none of those,
-`python tools/fetch_platform_tools.py` fetches it — 7 MB, straight from Google.
+`adb shell input tap` starts a process on the device per call, 100–300 ms each.
+This sends the whole drawing at once instead, and a stroke that takes 40 seconds
+through `input swipe` finishes in well under a second.
-```bash
-pip install pyinstaller
-python tools/build_app.py --msi # Windows: engine, WinUI front end, installer
-python tools/build_macos.py --dmg # macOS: the bundle and its disk image
-```
-
-The installer needs WiX: `dotnet tool install --global wix --version 5.0.2`.
-[Releasing](docs/RELEASING.md) covers the rest.
-
-
+**[How it works →](docs/INTERNALS.md)** — the digitizer's own coordinate space,
+the three ways into a device and why a recent Pixel refuses the fast one, what
+"instant" actually costs, drawing like a hand, and the open ends.
-Command line — every command, and the options they share
+Command line
@@ -188,92 +91,88 @@ The installer needs WiX: `dotnet tool install --global wix --version 5.0.2`.
mthread devices # what is attached
mthread info # screen size and digitizer ranges
-mthread shape heart # heart, star, circle, square, polygon, spiral, wave
-mthread shape star --points 7 --rotate 20
-mthread text "hello world" # any font the machine has
+mthread shape star --points 7 --rotate 20 # heart, star, circle, square, polygon, spiral, wave
mthread text "signed" --font arial.ttf --scale 0.5 --y 0.8
-
-mthread record -o session.json # record until Enter
mthread play session.json --speed 0.5 --repeat 3
```
-Every drawing command takes the same placement options — `--scale`, `--rotate`,
-`--flip-x`, `--flip-y`, `--x`, `--y`, `--margin` — and `--speed`/`--human` for
-how it draws.
+Every drawing command shares the placement options `--scale`, `--rotate`,
+`--flip-x`, `--flip-y`, `--x`, `--y`, `--margin`, and `--speed`/`--human` for how
+it draws.
Text is rendered with a real font and then traced, which is why any font works
-and why letters come out as outlines: a filled glyph is a shape with an inside
-and an outside, and this draws with one finger.
+and why letters come out as outlines: a filled glyph has an inside and an
+outside, and this draws with one finger.
+
-Library — the whole API in ten lines
+From source, and building the apps yourself
-```python
-from mthread import Device, Recorder, Session, replay
+[`run.bat`](run.bat) on Windows and [`run.sh`](run.sh) elsewhere do everything:
+environment, dependencies, and `adb` if the machine has none. By hand:
-device = Device()
-print(device.screen_size, device.touch_device.path)
+```bash
+git clone https://github.com/MAXAWER/MThread-Draw.git && cd MThread-Draw
+pip install -e . # library only - no dependencies at all
+pip install -e ".[draw]" # + image tracing (OpenCV, NumPy, Pillow)
+```
-recorder = Recorder(device)
-recorder.start()
-input("Do something on the phone, then press Enter...")
-recorder.stop().save("flow.json")
+`adb` is looked for in `ADB_PATH`, inside a packaged build, your `PATH`, a
+`platform-tools` folder beside the working directory, then the usual SDK
+locations — or `python tools/fetch_platform_tools.py` fetches it, 7 MB from
+Google.
-replay(device, Session.load("flow.json"), speed=2.0, repeat=10)
+```bash
+pip install pyinstaller
+python tools/build_app.py --msi # Windows: engine, WinUI front end, installer
+python tools/build_macos.py --dmg # macOS: bundle and disk image
```
+The installer needs WiX: `dotnet tool install --global wix --version 5.0.2`.
+Details in [RELEASING.md](docs/RELEASING.md).
+
-Known limits, said plainly
+Limits, and what to do when touches land in the wrong place
-- **A recording does not know which way up the phone was.** Drawing follows the
- orientation; a recording holds fractions of the screen it was made on, so a
- portrait recording replayed in landscape lands sideways.
-- **Replay carries a fixed overhead.** Starting and stopping the on-device
- injector costs a second or two: the strokes and the gaps are faithful, the
- total is not.
-- **Stop is not instantaneous.** It cancels what has not been queued yet and the
- device finishes what it already has — about two seconds' worth.
+- **A recording does not know which way up the phone was** — replay in the
+ orientation you recorded in. Drawing itself does follow the orientation.
+- **Replay has a fixed overhead** of a second or two for the on-device injector:
+ the strokes and gaps are faithful, the total is not.
+- **Stop is not instantaneous.** It cancels what is not yet queued; the device
+ finishes the two seconds it already has.
- **Recordings from before 1.2 are not portable** and say so rather than
misfiring.
-- **`mthread info` is the first thing to check** when touches land in the wrong
- place.
-
-
-
----
+- **Start with `mthread info`.** Then open an issue — templates for
+ [bugs](https://github.com/MAXAWER/MThread-Draw/issues/new?template=bug_report.md)
+ and [devices](https://github.com/MAXAWER/MThread-Draw/issues/new?template=device_report.md).
+ Digitizer ranges differ wildly between panels, and only what people report can
+ be fixed.
-## Help, and helping
+Works with any device `adb devices` lists, and with emulators that expose an ADB
+port — AVD, BlueStacks, LDPlayer (`:5555`), Nox (`:62001`), MEmu (`:21503`).
+PNG, JPEG, BMP, WebP. Python 3.9+.
-Something not working? Open an issue — there are templates for
-[bugs](https://github.com/MAXAWER/MThread-Draw/issues/new?template=bug_report.md)
-and [device reports](https://github.com/MAXAWER/MThread-Draw/issues/new?template=device_report.md).
-Paste the output of `mthread info`; digitizer ranges differ wildly between
-panels, and only what people report can be handled.
-
-Contributions welcome — [CONTRIBUTING.md](CONTRIBUTING.md), and
-[`good first issue`](https://github.com/MAXAWER/MThread-Draw/labels/good%20first%20issue)
-is the easiest way in. [What is worth doing next →](docs/INTERNALS.md#open-ends)
+
## Licence
-**AGPL-3.0, with a commercial licence available from the author.** Use it, change
-it, share it, free of charge — but a version you **distribute**, or **run as a
-service** other people use, has to publish its complete source under the AGPL
-too, a rebranded copy included. To put it inside a product whose source stays
-closed, [ask for a commercial licence](https://github.com/MAXAWER/MThread-Draw/issues/new?title=Licence%20request).
-
-Binding text: [LICENSE](LICENSE). Plain language, English and Russian:
-**[TERMS.md](TERMS.md)**.
+**AGPL-3.0, with a commercial licence available from the author.** Free to use,
+change and share — but anything you **distribute**, or **run as a service**
+others use, must publish its complete source under the AGPL, a rebranded copy
+included. For a product whose source stays closed,
+[ask for a commercial licence](https://github.com/MAXAWER/MThread-Draw/issues/new?title=Licence%20request).
+Binding text: [LICENSE](LICENSE) · plain language: [TERMS.md](TERMS.md) ·
+contributing: [CONTRIBUTING.md](CONTRIBUTING.md).
-If this saved you an afternoon, a ⭐ costs nothing and is how anyone else finds it.
+If this saved you an afternoon, a ⭐ is how anyone else finds it.
diff --git a/README.ru.md b/README.ru.md
index 764a7b4..9e0363d 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -4,14 +4,14 @@
-Рисунок выше рисует себя сам, и это не иллюстрация: это те самые 232 штриха, которые
-tools/make_hero.py получает из examples/motorcycle.jpg — в том порядке, в котором программа отправляет их на телефон.
+Не иллюстрация — 232 настоящих штриха из examples/motorcycle.jpg, в том порядке, в котором они уходят на телефон.
-
-
-
+
+
+
+
@@ -19,58 +19,45 @@
-
-### Рисует картинки на экране Android, касаясь его,
записывает и повторяет жесты. На телефон ничего не ставится.
+### Рисует любую картинку на экране Android, касаясь его.
Записывает и повторяет жесты. На телефон ничего не ставится.
-USB или ADB по Wi-Fi · на большинстве устройств без root · без Android SDK · одна загрузка, всё внутри
+USB или ADB по Wi-Fi · на большинстве устройств без root · без Android SDK · Python, OpenCV и adb лежат внутри приложения
-
+
-На входе фотография, на выходе 57 штрихов и 478 точек касания — ровно тот список путей, что уходит на устройство.
-На Pixel 8 Pro это рисуется меньше чем за две секунды.
+57 штрихов, 478 точек — ровно тот список путей, что уходит на устройство. На Pixel 8 Pro меньше двух секунд.
----
+## Начать
-## Примерно за минуту
-
-| | |
+| | |
|---|---|
-| **1 · Установить** | [**Windows**](https://github.com/MAXAWER/MThread-Draw/releases/latest) — `MThreadDraw-x.y.z-x64.msi`, с ярлыком в «Пуске» и деинсталлятором. [**macOS**](https://github.com/MAXAWER/MThread-Draw/releases/latest) — `.dmg` для Apple Silicon или Intel, перетащить в Applications. **Linux** — командная строка, [из исходников](#из-исходников). |
-| **2 · Разбудить телефон** | Настройки → О телефоне → семь раз по «Номер сборки» → Для разработчиков → **Отладка по USB**. Подключить кабель или `adb connect 192.168.1.42:5555`. |
-| **3 · Рисовать** | Телефон находится сам, экран показывается живьём, рисунок ложится поверх того места, куда попадёт. Тащить мышью, колесо — размер, Shift с колесом — поворот, затем **START DRAWING**. |
-
-**Больше ничего ставить не нужно.** Python, OpenCV и **adb** лежат внутри самого
-приложения. Оба окна нативные — **WinUI 3** на Windows и **SwiftUI** на macOS — и
-оба разговаривают с одним и тем же движком по каналу, так что у них не может
-быть разных представлений о происходящем. Сборки не подписаны: Windows один раз
-скажет «неизвестный издатель», а macOS попросит первый запуск через правую
-кнопку → **Открыть**.
+| **1** | Установить: [Windows `.msi`](https://github.com/MAXAWER/MThread-Draw/releases/latest) · [macOS `.dmg`](https://github.com/MAXAWER/MThread-Draw/releases/latest) · Linux — [из исходников](#из-исходников). Подписи нет, поэтому Windows один раз скажет «неизвестный издатель», а macOS попросит правую кнопку → **Открыть**. |
+| **2** | На телефоне: Настройки → О телефоне → **Номер сборки** ×7 → Для разработчиков → **Отладка по USB**. Подключить кабель или `adb connect 192.168.1.42:5555`. |
+| **3** | Открыть. Тащить рисунок по живому экрану, колесо — размер, Shift+колесо — поворот, затем **START DRAWING**. |
----
+## Что умеет
-## Что можно сделать в окне
-
-| | |
+| | |
|---|---|
-| **Разместить точно** | Перетаскивание по живому экрану; колесо — размер, Shift с колесом — поворот, `Flip` — отражение, `Fit` — вписать заново. Положение хранится в долях экрана и переживает поворот телефона. |
-| **Слои** | Несколько картинок друг относительно друга, у каждой своё положение и свои настройки трассировки. Слой можно спрятать, переставить, удалить. |
-| **Ластик по штрихам** | Включить ластик и провести по ненужным линиям; `Undo erase` возвращает их. |
-| **Пересчёт на месте** | Ползунок детализации перетрассирует уже загруженное — открывать файл заново не нужно. |
-| **Запись и повтор** | Нажать запись, поделать что-нибудь на телефоне, остановить. Файл хранит доли экрана, поэтому **воспроизводится на другом телефоне**, с любой скоростью и сколько угодно раз. |
-| **Нет живого экрана?** | Если захват не работает, подойдёт снимок, снятый на телефоне вручную: он не обновляется, но его пропорции — это то, что нужно для размещения. |
-
-Ничего не готовя — из командной строки или из кода:
+| **Размещение мышью** | Тащить, менять размер, поворачивать, отражать, `Fit`. Хранится в долях экрана и переживает поворот телефона. |
+| **Слои** | Несколько картинок сразу, у каждой своё положение и свои настройки трассировки. |
+| **Ластик по штрихам** | Провести по ненужным линиям; `Undo erase` возвращает их. |
+| **Пересчёт на месте** | Ползунок детализации перетрассирует загруженное — заново открывать файл не нужно. |
+| **Запись и повтор** | Файл хранит доли экрана, поэтому **воспроизводится на другом телефоне**, с любой скоростью. |
+| **Два трассировщика** | Кэнни для техники и зданий, когерентные линии по потоку для лиц и животных. Приложение спрашивает, что на картинке, а не какой алгоритм. |
+| **Нативные окна** | WinUI 3 на Windows, SwiftUI на macOS, оба поверх одного движка. |
+| **Нет живого экрана?** | Подойдёт снимок, снятый на телефоне вручную — важны его пропорции. |
```bash
mthread shape heart # сердце, вписанное в экран
-mthread text "привет" --y 0.35 # текст любым шрифтом, что есть в системе
+mthread text "привет" --y 0.35 # любым шрифтом, что есть в системе
mthread record -o login.json # затем: mthread play login.json --speed 2
```
@@ -79,69 +66,46 @@ from mthread import Device
Device().draw_paths([[(100, 200), (400, 200), (400, 600)]])
```
----
-
-## Как фотография превращается в касания
-
-

-
-
-Трассировщик находит линии, результат утончается до одного пикселя, и каждая
-линия проходится одним штрихом — не обводится по контуру, иначе всё рисовалось бы
-дважды. Выше — `examples/guitar.jpg` без единой правки: 57 штрихов, 478 точек.
+
-Приложение спрашивает не про алгоритм, а про то, что на фотографии:
-
-| Что на фотографии | Что работает | Почему именно это |
-|---|---|---|
-| **Здания, техника, объекты** | Границы по Кэнни, утончение, обход в штрихи | Сохраняет всю структуру, которую видит детектор границ, — а машина или башня из неё и состоит. |
-| **Портреты, животные, природа** | Когерентные линии по направлению потока | Считает, куда идёт каждая линия, и фильтрует вдоль неё: штрихи длиннее и спокойнее, лицо остаётся лицом, а не зерном плёнки. |
-
-Ни один не выигрывает везде — поэтому остались оба. Теряется цвет: палец рисует
-одну чёрную линию, поэтому результат всегда штриховой.
-
-
-

-
-
Ничего не готовилось и не ретушировалось — это файлы из examples/, только уменьшенные.
-Между колонками отличаются лишь те два ползунка, что есть у любого пользователя.
+
Это файлы из examples/, только уменьшенные — ничего не готовилось, не ретушировалось и не вырезалось.
----
+## Почему это быстро
-## Зачем это нужно
+`adb shell input tap` запускает на устройстве отдельный процесс на каждый вызов —
+100–300 мс за штуку. Здесь весь рисунок уходит целиком, и штрих, который через
+`input swipe` рисуется 40 секунд, занимает меньше секунды.
-`adb shell input tap` запускает отдельный процесс на устройстве при каждом
-вызове — 100–300 мс на команду, и для чего-либо непрерывного это неприемлемо
-медленно. `mthread` отправляет весь рисунок на устройство целиком: события ядра
-одним загруженным сценарием там, где телефон это позволяет, и инжектор на 3 КБ
-через `app_process` там, где нет. Штрих, который через `input swipe` рисуется
-40 секунд, здесь занимает меньше секунды.
+**[Как это устроено →](docs/INTERNALS.md)** (по-английски) — своя система
+координат у тачскрина, три пути внутрь устройства и почему свежий Pixel
+отказывает в самом быстром, чего стоит «мгновенно», рисование по-человечески и
+список открытых задач.
-Две части, и любая работает без другой: **`mthread`** — библиотека
-синтетического ввода касаний, ядру которой не нужно вообще никаких зависимостей,
-и **MThread Draw** — приложение поверх неё.
+
+Командная строка
-**[Как это устроено, подробно →](docs/INTERNALS.md)** (по-английски) — своя
-система координат у тачскрина, три пути внутрь устройства и почему свежий Pixel
-отказывает в самом быстром, чего стоит «мгновенно» и как это рисует по-человечески.
+
----
+```bash
+mthread devices # какие устройства подключены
+mthread info # разрешение экрана и диапазоны тачскрина
-## С чем работает
+mthread shape star --points 7 --rotate 20 # heart, star, circle, square, polygon, spiral, wave
+mthread text "подпись" --font arial.ttf --scale 0.5 --y 0.8
+mthread play session.json --speed 0.5 --repeat 3
+```
-| | |
-|---|---|
-| **Устройства** | Всё, что видно в `adb devices` — по USB или по Wi-Fi. На большинстве устройств root не нужен. |
-| **Эмуляторы** | Android Studio AVD, BlueStacks (`:5555`), LDPlayer (`:5555`), Nox (`:62001`), MEmu (`:21503`). Поддержка сырого `/dev/input` отличается от сборки к сборке — `mthread info` покажет за одну строку. |
-| **Картинки** | PNG, JPEG, BMP, WebP. Пока только растр. |
-| **Хост** | Windows, macOS, Linux. Python 3.9+. |
+У всех команд рисования общие параметры размещения `--scale`, `--rotate`,
+`--flip-x`, `--flip-y`, `--x`, `--y`, `--margin` и `--speed`/`--human` — как
+рисовать.
+
+Текст рисуется настоящим шрифтом и затем трассируется: поэтому доступен любой
+шрифт системы и поэтому буквы выходят контурами — у залитой глифы есть внутренняя
+и внешняя граница, а здесь рисует один палец.
-Используют для рисовалок и досок на телефоне, подписей и штампов, тестовых
-прогонов, где записанный сценарий повторяют на каждой сборке, и однообразных
-нажатий там, где других способов автоматизации нет. Допустимо ли автоматизировать
-конкретную игру — вопрос её правил; это инструмент ввода общего назначения.
+
@@ -150,21 +114,17 @@ Device().draw_paths([[(100, 200), (400, 200), (400, 600)]])
[`run.bat`](run.bat) на Windows и [`run.sh`](run.sh) на macOS и Linux делают всё
-сами: окружение, зависимости и `adb`, если своего нет. Иначе вручную:
+сами: окружение, зависимости и `adb`, если своего нет. Вручную:
```bash
-git clone https://github.com/MAXAWER/MThread-Draw.git
-cd MThread-Draw
-
+git clone https://github.com/MAXAWER/MThread-Draw.git && cd MThread-Draw
pip install -e . # только библиотека - зависимостей нет вообще
pip install -e ".[draw]" # + трассировка картинок (OpenCV, NumPy, Pillow)
-pip install -e ".[bg]" # + удаление фона (rembg)
```
-`adb` ищется по порядку: `ADB_PATH`, копия внутри собранного приложения, ваш
-`PATH`, папка `platform-tools` рядом с рабочим каталогом, затем обычные пути
-Android SDK. Если ничего из этого нет, `python tools/fetch_platform_tools.py`
-скачает его — 7 МБ, прямо от Google.
+`adb` ищется в `ADB_PATH`, внутри собранного приложения, в вашем `PATH`, в папке
+`platform-tools` рядом с рабочим каталогом, затем в обычных путях SDK — или
+`python tools/fetch_platform_tools.py` скачает его, 7 МБ от Google.
```bash
pip install pyinstaller
@@ -177,98 +137,41 @@ python tools/build_macos.py --dmg # macOS: бандл и образ диска
-Командная строка — все команды и общие параметры
-
-
-
-```bash
-mthread devices # какие устройства подключены
-mthread info # разрешение экрана и диапазоны тачскрина
-
-mthread shape heart # heart, star, circle, square, polygon, spiral, wave
-mthread shape star --points 7 --rotate 20
-mthread text "привет" # текст любым шрифтом, что есть в системе
-mthread text "подпись" --font arial.ttf --scale 0.5 --y 0.8
-
-mthread record -o session.json # запись до нажатия Enter
-mthread play session.json --speed 2 --repeat 5
-```
-
-У всех команд рисования одни и те же параметры размещения — `--scale`,
-`--rotate`, `--flip-x`, `--flip-y`, `--x`, `--y`, `--margin` — и
-`--speed`/`--human`, отвечающие за то, как рисовать.
-
-Текст рисуется настоящим шрифтом и затем трассируется — поэтому доступен любой
-шрифт системы, и поэтому буквы выходят контурами: залитая глифа это фигура с
-внутренней и внешней границей, а здесь рисует один палец.
-
-
-
-
-Библиотека — весь интерфейс в десяти строках
+Ограничения и что делать, если касания попадают не туда
-```python
-from mthread import Device, Recorder, Session, replay
-
-device = Device()
-print(device.screen_size, device.touch_device.path)
-
-recorder = Recorder(device)
-recorder.start()
-input("Сделайте что-нибудь на телефоне и нажмите Enter...")
-recorder.stop().save("flow.json")
-
-replay(device, Session.load("flow.json"), speed=2.0, repeat=10)
-```
-
-
-
-
-Ограничения, честно
-
-
-
-- **Запись не знает, как был повёрнут телефон.** Рисование ориентацию учитывает,
- а запись хранит доли того экрана, на котором сделана, поэтому портретная
- запись в горизонтальной ориентации ляжет набок.
+- **Запись не знает, как был повёрнут телефон** — воспроизводите в той же
+ ориентации, в которой записывали. Само рисование ориентацию учитывает.
- **У воспроизведения есть постоянная накладная стоимость** — секунда-две на
- запуск и остановку инжектора. Штрихи и паузы точны, общая длительность нет.
-- **Стоп не мгновенный.** Он отменяет то, что ещё не отправлено, а устройство
- дорисовывает уже полученное — около двух секунд.
+ инжектор: штрихи и паузы точны, общая длительность нет.
+- **Стоп не мгновенный.** Он отменяет то, что ещё не отправлено; уже полученные
+ две секунды устройство дорисует.
- **Записи старше 1.2 не переносятся** между телефонами и честно об этом
сообщают, а не рисуют мимо.
-- **Начинайте с `mthread info`**, если касания попадают не туда.
-
-
-
----
+- **Начните с `mthread info`.** Дальше — issue, есть шаблоны для
+ [багов](https://github.com/MAXAWER/MThread-Draw/issues/new?template=bug_report.md)
+ и [устройств](https://github.com/MAXAWER/MThread-Draw/issues/new?template=device_report.md).
+ Диапазоны координат тачскрина у разных панелей разные, и починить можно только
+ то, что видно.
-## Помощь и участие
+Работает с любым устройством из `adb devices` и с эмуляторами, открывающими порт
+ADB — AVD, BlueStacks, LDPlayer (`:5555`), Nox (`:62001`), MEmu (`:21503`).
+PNG, JPEG, BMP, WebP. Python 3.9+.
-Что-то не работает — заведите issue, есть шаблоны для
-[багов](https://github.com/MAXAWER/MThread-Draw/issues/new?template=bug_report.md)
-и [отчётов об устройстве](https://github.com/MAXAWER/MThread-Draw/issues/new?template=device_report.md).
-Приложите вывод `mthread info`: диапазоны координат тачскрина у разных панелей
-разные, и починить можно только то, что видно.
-
-Участие приветствуется — [CONTRIBUTING.md](CONTRIBUTING.md), а метка
-[`good first issue`](https://github.com/MAXAWER/MThread-Draw/labels/good%20first%20issue)
-самый простой вход.
+
## Лицензия
-**AGPL-3.0 плюс коммерческая лицензия от автора.** Пользуйтесь, меняйте,
-делитесь, бесплатно — но распространяемая версия и сервис на её основе обязаны
-опубликовать полный исходный код под AGPL, включая перекрашенную копию. Чтобы
-встроить в продукт с закрытым кодом, нужна
+**AGPL-3.0 плюс коммерческая лицензия от автора.** Пользоваться, менять и
+делиться — бесплатно, но всё, что вы **распространяете** или **держите сервисом**
+для других, обязано публиковать полный исходный код под AGPL, включая
+перекрашенную копию. Для продукта с закрытым кодом нужна
[коммерческая лицензия](https://github.com/MAXAWER/MThread-Draw/issues/new?title=Licence%20request).
-
-Юридический текст: [LICENSE](LICENSE). Человеческим языком, по-русски и
-по-английски: **[TERMS.md](TERMS.md)**.
+Юридический текст: [LICENSE](LICENSE) · человеческим языком:
+[TERMS.md](TERMS.md) · участие: [CONTRIBUTING.md](CONTRIBUTING.md).
-Если инструмент сэкономил вам вечер — звезда ⭐ ничего не стоит, а найти проект другим людям помогает.
+Если инструмент сэкономил вам вечер — звезда ⭐ помогает найти его другим.
diff --git a/mthread/__init__.py b/mthread/__init__.py
index 0abe3ad..434819f 100644
--- a/mthread/__init__.py
+++ b/mthread/__init__.py
@@ -36,7 +36,7 @@
from .session import InputEvent, Session
from .touch import TouchDevice, build_stroke_events, parse_getevent_pl, pick_touchscreen
-__version__ = "1.2.0"
+__version__ = "1.3.0"
#: AGPL-3.0, with a commercial licence available from the author for use in
#: products that will not publish their source. See TERMS.md.
diff --git a/mthread_draw/__init__.py b/mthread_draw/__init__.py
index 54b99c7..e31bc88 100644
--- a/mthread_draw/__init__.py
+++ b/mthread_draw/__init__.py
@@ -3,4 +3,4 @@
Draws images on an Android device and records / replays touch gestures.
"""
-__version__ = "1.2.0"
+__version__ = "1.3.0"