Releases: Freakz2z/OpenColor
OpenColor v0.2.2
Cross-platform OpenColor installers and packages.
OpenColor v0.2.1
OpenColor v0.2.1
Lightweight cross-platform color picker for VibeCoding.
轻量级跨平台提色器,为 VibeCoding 而生。
English
A small polish release — no new features, just better internals and a smoother picker.
Highlights
- Smoother picker drag — the 30 Hz capture loop now skips
set_positionandpicker://pixelemit when the cursor hasn't actually moved or the pixel under it hasn't changed. The picker card no longer fights the IPC + window-manager roundtrip on every tick; stationary moments do zero JS work. - macOS permission re-check on demand — the "Open System Settings" button on the permission banner now uses a custom Rust command that bypasses the
tauri-plugin-openerURL scheme scope, so the deep link actually opens Settings. Clicking the pick button after granting Screen Recording no longer requires an app restart — Rust re-runs the preflight and updates the cached permission state in place. - Release workflow hardened — the release job now
needstwo new gate jobs (frontend vitest/build + rust fmt/check/clippy/test on a 2-OS matrix). Bad code can no longer ship to the GitHub Release.
Optimizations
Toolbar.tsxno longer re-exports 12 lucide icons it never used; App.tsx imports them directly.useMemofor the active palette lookup, the ColorGrid family bucket Map, and the family filter — keystrokes and dialog toggles no longer rebuild the Map.useCallbackfor the three handlers passed across the App → ColorGrid boundary, ready for downstreamReact.memo.useState<Set<number>>(() => new Set())lazy init for the image-import selection set.
Error handling
- New
errMsg(e: unknown): stringhelper replaces 4 unsafe(e as Error).messagesites inApp.tsxand 1 inImageImportDialog. Tauri's IPC can throw plain strings from RustErr("…"), where.messagewould beundefinedand the status bar would render literalundefined. 4 unit tests cover the helper. runWithErrorToast+persistOrDemoEdithelpers collapse the demo-vs-persisted branching across 6 CRUD handlers.handleRenamePaletteandhandleDeleteColornow get automatic error toasts where they previously had none.
i18n
colorCard.editkey added in bothen.jsonandzh-CN.json— the edit button'stitleattribute was rendering the raw key.
Internal cleanup
storage::list_all<T>dead helper removed (#[allow(dead_code)]was masking it).
CI / docs
vitestnow has 8/8 green unit tests (format,reorder).- README header gained a shields.io badge row (Release, CI, License, Tauri/React/Rust, Platform) + extra nav links (Contributing, Releases, Changelog).
- Logo pinned to 80×80 via inline
<img>.
中文
小版本优化 —— 没有新功能,主要是把内部做干净、取色器拖动更顺。
重点
- 取色器拖动更顺 —— 30Hz 的捕获循环现在会在光标位置或像素颜色未变时,跳过
set_position和picker://pixel事件分发。取色卡不再每个 tick 都跟 IPC + 窗口管理器抢资源,光标静止时主线程零 JS 工作。 - macOS 权限按需重检 —— 权限横幅上的「打开系统设置」按钮改用一个自定义 Rust 命令,绕开
tauri-plugin-opener的 URL scheme 限制,深链能真正打开 Settings。在「屏幕录制」授权后再次点击取色按钮不再需要重启 App —— Rust 会现场重跑 preflight 并就地更新缓存的权限状态。 - 发布流程加固 —— Release job 现在
needs两个新 gate job(前端 vitest/build + Rust 在 2 平台跑 fmt/check/clippy/test)。有问题的代码不会再溜进 GitHub Release。
性能优化
Toolbar.tsx不再 re-export 12 个根本没被消费的 lucide 图标;App.tsx 直接 import 它们。- 给 active 调色板查找、ColorGrid 的色族分桶 Map、色族列表过滤加
useMemo—— 输入和 dialog 切换不再触发重建。 - 三个跨 App → ColorGrid 边界传递的 handler 包
useCallback,下游以后想加React.memo不用改 deps。 useState<Set<number>>(() => new Set())改成 lazy init。
错误处理
- 新增
errMsg(e: unknown): stringhelper,替换App.tsx里 4 处不安全的(e as Error).message和ImageImportDialog里的 1 处。Tauri IPC 可能从 Rust 抛字符串错误(Err("…")),那种情况下.message是undefined,状态条会渲染出字面量undefined。helper 配 4 个单元测试。 - 新增
runWithErrorToast+persistOrDemoEdithelper,把 6 个 CRUD handler 的 demo-vs-persisted 分支折叠。handleRenamePalette和handleDeleteColor现在自动有错误 toast 了,之前是裸调。
i18n
colorCard.editkey 在两个 locale 都补上 —— 编辑按钮的title之前显示的是原始 key。
内部清理
- 删
storage::list_all<T>死代码(#[allow(dead_code)]一直在掩盖它)。
CI / 文档
vitest8/8 全绿(format、reorder)。- README 头部加 shields.io 徽章行(Release、CI、License、Tauri/React/Rust、Platform)+ 额外导航链接(Contributing、Releases、Changelog)。
- Logo 通过 inline
<img>钉死 80×80。
Checksums / 校验和
# Will be generated by tauri-action after the draft is created.
# tauri-action 会在草稿创建后自动生成。
Full Changelog: v0.2.0...v0.2.1
OpenColor v0.2.0
OpenColor v0.2.0
Lightweight cross-platform color picker for VibeCoding.
轻量级跨平台提色器,为 VibeCoding 而生。
English
This release stabilises the picker, ships drag-and-drop palette reordering, and adds a real cross-platform release pipeline.
Picker reliability
The picker module has been rewritten to use a session-id + atomic state machine, replacing the previous simple mutex:
session_id+take(expected)— every start bumps a session counter; only the matching session can finish, so a stale cancel from a previous pick can no longer clobber the new one.- Atomic
TAP_STATE(NOT_STARTED / STARTING / RUNNING / FAILED) — therdevglobal tap listener is guarded so a secondstart()from a double-click is rejected instead of spawning a second CFRunLoop thread (which would have leaked forever). - Defensive
finish_session(PickOutcome)— picked, cancelled, and silent outcomes all funnel through one path that restores the main window, so the picker no longer leaves the main window hidden under Accessory activation policy on macOS. - Click-arm debounce (250 ms) — the first click after
startis ignored, so activating the picker from the toolbar doesn't immediately commit a stray pick. - Capture throttled to ~30 Hz (was ~60 Hz) — no perceivable quality loss and far less load on the screen-capture API.
Picker UX fixes
set_picker_mode(false)now reliably hides the main window — previously the main window could stay on top when the activation policy was toggled.- Double-clicking the picker button no longer causes a hide→show flash.
- Drag-reordering no longer races a palette reload.
- The full palette card is now draggable, not just the 14×14 grip handle (which was
display: nonebelow 640 px). - Container-level
dragover/dropfallback — dropping between cards still reorders. - Redundant toolbar buttons on each palette card removed.
Cross-platform release pipeline (new)
A new Release GitHub Actions workflow builds and uploads installers for:
- Windows (
.msi/.exeonwindows-latest) - macOS Intel (
.dmgx86_64 onmacos-15-intel) - macOS Apple Silicon (
.dmgaarch64 onmacos-latest)
Linux note: the workflow is wired to also build
.deb/.AppImageonubuntu-22.04, but that job is currently failing in the upstreamlibspa 0.9.2crate (broken bindgen output against modernrustc— seenashaofu/xcapissue #247). Linux installers will follow in the next patch release once the upstream is fixed. The macOS / Windows builds in this release are unaffected.
Pushing an annotated v* tag triggers the matrix build and auto-creates a draft release with all artefacts attached via tauri-action.
CI
- CI now also runs
pnpm test(vitest) andcargo test --all-targetsin addition to build / check / clippy. - Added Linux CI deps:
libpipewire-0.3-dev,libgbm-dev,libx11-dev,libxtst-dev,libxcb-cursor0,libxcb-cursor-devso the Linux build is no longer linker-fragile. dist/picker.htmlis verified to exist aftervite buildso the picker window can no longer silently ship without its bundle.
Internals
order.jsonstorage for palette order — reorders persist across launches; self-heals if a referenced palette is deleted.vitest+ jsdom scaffold with smoke tests forformatandreorder.- React 18 / Tauri 2 / i18next (en + zh-CN) / lucide-react, MIT licensed.
Installers
See the assets below for your platform. The draft is not yet published — review the notes and the built artefacts, then Publish release when you're ready.
中文
本次发布稳定了取色器、加入了调色板拖拽排序,并补齐了真正的跨平台发布流水线。
取色器稳定性
picker.rs 整个重写为 session-id + 原子状态机,替换了原本的简单 mutex:
session_id+take(expected)— 每次start递增 session 计数,只有匹配的 session 才能finish,上一轮取色的迟到 cancel 不再能污染新一轮。- 原子
TAP_STATE(NOT_STARTED / STARTING / RUNNING / FAILED) —rdev全局 tap 监听器加了守卫,双击触发的第二次start()会被直接拒绝,不会再起第二条 CFRunLoop 线程(那条线之前会永久泄漏)。 finish_session(PickOutcome)统一出口 — 拾取、取消、静默退出都走同一条恢复主窗口的路径,取色器不会再让主窗口留在 macOS 的 Accessory 激活策略下变没响应。- 点击去抖 250 ms —
start之后的第一击会被忽略,从工具栏启动取色不会再被误判成一取。 - 截图频率从 ~60 Hz 降到 ~30 Hz — 画质无可感损失,但屏幕捕获 API 压力大幅下降。
取色器 UX 修复
set_picker_mode(false)现在能稳定隐藏主窗口 —— 之前在 macOS 上偶尔会留在最上层。- 双击取色器按钮不再出现「隐藏→又显示」的闪烁。
- 拖拽排序不再和调色板 reload 抢资源。
- 整张调色板卡片都可拖拽,不再只靠 14×14 的小把手(而且小把手在 640px 以下还会
display: none)。 - 容器级
dragover/drop兜底 —— 卡片之间空隙处的拖入也能正确排序。 - 移除了调色板卡片上多余的按钮。
跨平台发布流水线(新增)
全新的 Release GitHub Actions 工作流,目前覆盖 3 个目标平台:
- Windows(
windows-latest,.msi/.exe) - macOS Intel(
macos-15-intel,x86_64.dmg) - macOS Apple Silicon(
macos-latest,aarch64.dmg)
Linux 说明:workflow 里其实也配置了
ubuntu-22.04的.deb/.AppImage任务,但目前该 job 在上游libspa 0.9.2crate 编译失败(对现代rustc的 bindgen 输出有 bug,见nashaofu/xcapissue #247)。Linux 安装包将在下个 patch 版本中跟上 —— 等上游修复后即刻补齐。本次的 macOS / Windows 构建不受影响。
推送带注释的 v* tag 就会触发矩阵构建,并通过 tauri-action 自动创建草稿 release、附带全部产物。
CI
- CI 现在除了 build / check / clippy 之外,还会跑
pnpm test(vitest)和cargo test --all-targets。 - 补齐 Linux CI 依赖:
libpipewire-0.3-dev、libgbm-dev、libx11-dev、libxtst-dev、libxcb-cursor0、libxcb-cursor-dev,Linux 构建不再因为缺系统库翻车。 vite build之后断言dist/picker.html存在 —— 取色器窗口的 bundle 不再会「莫名消失」。
内部细节
order.json持久化调色板顺序,重启后保留;引用了已删除 palette 时自动愈合。- 引入
vitest+ jsdom,并为format和reorder写了冒烟测试。 - React 18 / Tauri 2 / i18next(en + zh-CN)/ lucide-react,MIT 协议。
安装包
下方 Assets 区域按平台分类。草稿尚未发布 —— 请先 review 一下说明和构建产物,满意后再点 Publish release。
Checksums / 校验和
# Will be generated by tauri-action after the draft is created.
# tauri-action 会在草稿创建后自动生成。
Full Changelog: https://github.com/Freakz2z/OpenColor/commits/main
Initial public release. / 首个公开发布。