TC002 desktop installer¶
The desktop installer puts AWTRIX NG on a Ulanzi TC002 over USB. It needs no stock Wi-Fi setup,
Android SDK, ADB, Python or WSL. It catches the stock firmware's short USB window, prepares the
application image, and asks before writing the clock. Optional Wi-Fi settings are sent over USB
after AWTRIX starts; if they are left empty, AWTRIX opens its setup access point, which is also the
way back when the saved network is unavailable. The source lives in
tools/tc002/desktop/.
How it works¶
There are two programs:
- The graphical installer uses Tauri and the operating system's webview. It carries no Chromium and no firmware image.
- The terminal installer (
awtrix-tc002-installer-cli) walks through the same USB installation and optional Wi-Fi setup without a graphical session or WebKit. It runs on Node.js 24 or newer when present, or prepares a pinned, hash-checked official Node.js runtime from a local archive or an automatic download.
Both use the same image-building and installation engine as the browser installer, including the
WebAssembly browser image tools that build the res image. The native side
(Rust, in native/) handles USB, downloads and runtime extraction.
Firmware selection follows this order:
- an explicitly chosen file (Choose firmware ZIP… in the app,
--firmware PATHin the terminal); usb-awtrix-ng-tc002.zipbeside the program;- a download from the latest stable GitHub release, checked against its published digest.
Every route checks the TC002 package contents. A missing, unreadable or invalid chosen or automatically found ZIP stops installation without falling back to the next source. Wi-Fi passwords are never passed as command-line arguments or stored in an installer configuration file.
Downloads¶
Every release carries the installers
with version-free file names, the source archive for each platform and
AWTRIX-NG-TC002-Installer-manifest.json (version, commit, sizes and SHA-256).
| System | Graphical installer | Terminal version |
|---|---|---|
| Windows 10/11, x64 | Standalone EXE | ZIP containing the CLI EXE |
| macOS 13.5+, Intel or Apple silicon | DMG for the matching processor | tar.gz for the matching processor |
| Linux, x64 or ARM64 | DEB or RPM | tar.gz for the matching processor |
- The Windows EXE runs from any folder and installs nothing. It uses the installed WebView2 runtime, which Windows 11 and current Windows 10 contain; otherwise install the WebView2 Runtime.
- macOS uses the system WebKit.
- Linux packages depend on WebKitGTK 4.1 and GTK 3, which the package manager installs. The baseline is Ubuntu 22.04 / Debian 12 or newer; RPM-based distributions need compatible glibc, GTK 3 and WebKitGTK 4.1 packages.
The builds are unsigned, so Windows or macOS may ask for confirmation before opening them. There is no automatic application updater.
Run the terminal version from its extracted folder:
On Windows, use awtrix-tc002-installer-cli.exe. --help shows the options instead of starting
an installation; --version prints the version.
Offline use¶
Keep the TC002 firmware ZIP compressed. In the graphical app, press Choose firmware ZIP… and select it before connecting the clock. In the terminal version, pass its path:
Quote paths containing spaces. The chosen file takes priority over any ZIP beside the program
and over GitHub. Cancelling the graphical file dialog keeps the current choice. Retry firmware
rereads the chosen file; restart the app, or omit --firmware on the next terminal run, to return
to automatic selection.
For automatic discovery, name the file usb-awtrix-ng-tc002.zip and put it beside the
graphical or terminal executable:
- macOS graphical app: beside the
.app, outside the app itself. - Linux graphical packages: beside the installed executable, not beside the DEB or RPM file. The file dialog can select a ZIP from any folder.
The installer shows Local firmware and checks it before connecting to USB.
Offline graphical use needs the system webview already installed: WebView2 on Windows, the package dependencies on Linux.
The terminal version needs an installed Node.js 24+ or the matching original Node.js 24.21.0 archive beside its executable, left compressed; the installer verifies and prepares it.
| System | x64 archive | ARM64 archive |
|---|---|---|
| Windows | node-v24.21.0-win-x64.zip |
— |
| macOS | node-v24.21.0-darwin-x64.tar.gz |
node-v24.21.0-darwin-arm64.tar.gz |
| Linux | node-v24.21.0-linux-x64.tar.gz |
node-v24.21.0-linux-arm64.tar.gz |
The archives come from the official Node.js files. The TC002 guide has the end-user instructions.
Linux USB access¶
The DEB and RPM packages install a USB access rule restricted to 18d1:d002, the TC002's
vendor/product pair. After installing the package, reconnect the clock. An active local desktop
session gets access through systemd-logind.
The standalone Linux CLI archive contains the same rule and a short
README-LINUX.md.
From the extracted archive, install the rule once:
sudo install -D -m 0644 70-awtrix-tc002.rules /etc/udev/rules.d/70-awtrix-tc002.rules
sudo udevadm control --reload-rules
For SSH or a machine without a desktop session, also add your account to plugdev once:
sudo groupadd --system --force plugdev
sudo usermod -aG plugdev "$(id -un)"
sudo udevadm control --reload-rules
Log out completely and back in, then reconnect the clock. Run the installer as your normal user.
The rule uses mode 0660; other users and other USB devices get no general access.
Building¶
Build each graphical package on its own operating system. Install Node.js 22.15+, Rust 1.94.0 and the Tauri prerequisites. Windows needs the MSVC build tools; macOS needs Xcode's command-line tools. Linux GUI builds need the WebKitGTK 4.1 and GTK 3 development packages. A CLI-only build needs only the Rust toolchain and native linker.
Install the exact JavaScript dependencies and the test harness from the repository root:
npm ci --prefix tools/tc002/desktop
npm ci --prefix webui/test
node --test tools/tc002/desktop/test/*.test.*
Prepare the pinned image tools once on Linux (see browser image tools). The generated directory can be copied to the same location in a Windows or macOS checkout:
python3 tools/tc002/browser-image/build.py --work /tmp/tc002-image-build --output docs/assets/tc002/image
Keep its generated JavaScript, WASM, build.json, licence texts and source archives together;
their hashes are checked before packaging. No firmware ZIP or stock device image is a build input.
From tools/tc002/desktop, build into a new directory outside the checkout whose parent
exists:
| Option | Effect |
|---|---|
| (none) | The GUI app (standalone EXE on Windows, DMG on macOS, DEB and RPM on Linux), a separate terminal archive and a source archive. |
--cli-only |
Only the terminal application, without Tauri or a system webview. |
--target TRIPLE |
The Rust target. |
--bundles LIST |
dmg, deb, rpm, deb,rpm, or none to compile without a package. Windows always uses none. |
--stage-only |
Only prepare and verify the frontend assets. |
--output DIR |
Omitted: a fresh directory in the system temporary directory. |
CARGO_TARGET_DIR reuses an external Cargo build cache between builds. The script sets
AWTRIX_INSTALLER_ASSETS to the exact staged assets for both binaries and passes an absolute
frontendDist override to Tauri. Direct Cargo or Tauri builds need the same inputs; the checked-in
default ../dist is only a placeholder. Build and test commands never connect to a clock.
Output¶
| Path | Content |
|---|---|
artifacts/ |
The installers, terminal archive, matching source archive and manifests to publish together. |
frontend/ |
The exact embedded UI, CLI engine, shared installation code, WASM, image-tool sources and licence notices. No firmware, stock image or device data. |
build-manifest.json |
Installer commit and dirty state, target, runtime version, and each embedded file's source, byte count and SHA-256. |
artifact-manifest.json |
The final downloadable files with sizes and SHA-256. |
sources/ |
The application sources and the corresponding source archives of native dependencies with copyleft licences. |
The source archive includes REBUILD.md with the commands to rebuild its snapshot directly. Build
validation also checks that native sources did not change while the compiler ran.
Cargo dependencies are pinned by native/Cargo.lock. Packaging records their licence expressions
and includes their licence and copyright notices. The image-building WASM keeps its separate
GPL/LGPL notices and corresponding sources. The application is under the repository's licence.
CI¶
The installer workflow
builds the WASM once, runs the shared tests, then builds Windows x64, macOS Intel/ARM64 and Linux
x64/ARM64 packages on native runners. It uses no signing keys. On a v* tag the CI workflow runs
it and attaches the installers to the release.
Publishing¶
The release job stages the five platform artifacts with:
It checks every file against its artifact-manifest.json, requires all five to come from the
same clean commit and version, and writes the version-free files and
AWTRIX-NG-TC002-Installer-manifest.json into DIRECTORY. The
TC002 guide
links to these file names on the latest release.
Testing¶
All tests below use fake USB sessions or no USB at all. They do not cover physical USB discovery, drivers, flash writes or Wi-Fi setup on a real clock.
npm testintools/tc002/desktopruns the UI, native bridge, terminal flow and packaging tests. The terminal suite also builds a synthetic SquashFS image with the real WASM tools and verifies its hash, metadata, partition bounds and the release slot behind it. Build the image tools first.cargo test --locked --no-default-features --features cliinnativechecks the native USB lifecycle, descriptors, transfer bounds, download verification, runtime extraction and the terminal protocol. It never enumerates USB hardware and needs no desktop libraries.--check-releaseon the CLI executable checks the current GitHub download without opening USB. A missing TC002 asset is an expected failure while no matching public release exists.--helpand--versionneed neither a display nor network access.
Webview qualification¶
For a check of the real Tauri webview, build with the qualification Cargo feature and point
AWTRIX_QUALIFICATION_FIRMWARE, AWTRIX_QUALIFICATION_STOCK and AWTRIX_QUALIFICATION_REPORT at
a qualified TC002 test package (browser package format 2), the synthetic stock fixture and a new
report path. Run that executable on a desktop. It loads the real UI, binary IPC and WASM worker,
checks that the package's release image fits the release slot of the resulting image, compares
that image with the hash test/tauri-smoke.js pins from an independent native build of the same
package, writes its JSON report and exits. Qualifying another test package means pinning its
native hash there.
To qualify offline loading through the real native file reader, place usb-awtrix-ng-tc002.zip
beside the test executable and set AWTRIX_QUALIFICATION_SIDECAR=1. The report must name
Local firmware; without the sidecar the normal GitHub download path runs.
The qualification feature disables every hardware operation and is excluded from shipped
builds. Never distribute a qualification executable as an installer.