Skip to content

Releases: Freakz2z/OpenColor

OpenColor v0.2.2

28 Jun 22:01

Choose a tag to compare

Cross-platform OpenColor installers and packages.

OpenColor v0.2.1

27 Jun 09:05

Choose a tag to compare

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_position and picker://pixel emit 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-opener URL 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 needs two 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.tsx no longer re-exports 12 lucide icons it never used; App.tsx imports them directly.
  • useMemo for the active palette lookup, the ColorGrid family bucket Map, and the family filter — keystrokes and dialog toggles no longer rebuild the Map.
  • useCallback for the three handlers passed across the App → ColorGrid boundary, ready for downstream React.memo.
  • useState<Set<number>>(() => new Set()) lazy init for the image-import selection set.

Error handling

  • New errMsg(e: unknown): string helper replaces 4 unsafe (e as Error).message sites in App.tsx and 1 in ImageImportDialog. Tauri's IPC can throw plain strings from Rust Err("…"), where .message would be undefined and the status bar would render literal undefined. 4 unit tests cover the helper.
  • runWithErrorToast + persistOrDemoEdit helpers collapse the demo-vs-persisted branching across 6 CRUD handlers. handleRenamePalette and handleDeleteColor now get automatic error toasts where they previously had none.

i18n

  • colorCard.edit key added in both en.json and zh-CN.json — the edit button's title attribute was rendering the raw key.

Internal cleanup

  • storage::list_all<T> dead helper removed (#[allow(dead_code)] was masking it).

CI / docs

  • vitest now 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_positionpicker://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): string helper,替换 App.tsx 里 4 处不安全的 (e as Error).messageImageImportDialog 里的 1 处。Tauri IPC 可能从 Rust 抛字符串错误(Err("…")),那种情况下 .messageundefined,状态条会渲染出字面量 undefined。helper 配 4 个单元测试。
  • 新增 runWithErrorToast + persistOrDemoEdit helper,把 6 个 CRUD handler 的 demo-vs-persisted 分支折叠。handleRenamePalettehandleDeleteColor 现在自动有错误 toast 了,之前是裸调。

i18n

  • colorCard.edit key 在两个 locale 都补上 —— 编辑按钮的 title 之前显示的是原始 key。

内部清理

  • storage::list_all<T> 死代码(#[allow(dead_code)] 一直在掩盖它)。

CI / 文档

  • vitest 8/8 全绿(formatreorder)。
  • 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

27 Jun 05:03

Choose a tag to compare

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) — the rdev global tap listener is guarded so a second start() 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 start is 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: none below 640 px).
  • Container-level dragover / drop fallback — 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 / .exe on windows-latest)
  • macOS Intel (.dmg x86_64 on macos-15-intel)
  • macOS Apple Silicon (.dmg aarch64 on macos-latest)

Linux note: the workflow is wired to also build .deb / .AppImage on ubuntu-22.04, but that job is currently failing in the upstream libspa 0.9.2 crate (broken bindgen output against modern rustc — see nashaofu/xcap issue #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) and cargo test --all-targets in addition to build / check / clippy.
  • Added Linux CI deps: libpipewire-0.3-dev, libgbm-dev, libx11-dev, libxtst-dev, libxcb-cursor0, libxcb-cursor-dev so the Linux build is no longer linker-fragile.
  • dist/picker.html is verified to exist after vite build so the picker window can no longer silently ship without its bundle.

Internals

  • order.json storage for palette order — reorders persist across launches; self-heals if a referenced palette is deleted.
  • vitest + jsdom scaffold with smoke tests for format and reorder.
  • 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 msstart 之后的第一击会被忽略,从工具栏启动取色不会再被误判成一取。
  • 截图频率从 ~60 Hz 降到 ~30 Hz — 画质无可感损失,但屏幕捕获 API 压力大幅下降。

取色器 UX 修复

  • set_picker_mode(false) 现在能稳定隐藏主窗口 —— 之前在 macOS 上偶尔会留在最上层。
  • 双击取色器按钮不再出现「隐藏→又显示」的闪烁。
  • 拖拽排序不再和调色板 reload 抢资源。
  • 整张调色板卡片都可拖拽,不再只靠 14×14 的小把手(而且小把手在 640px 以下还会 display: none)。
  • 容器级 dragover / drop 兜底 —— 卡片之间空隙处的拖入也能正确排序。
  • 移除了调色板卡片上多余的按钮。

跨平台发布流水线(新增)

全新的 Release GitHub Actions 工作流,目前覆盖 3 个目标平台:

  • Windowswindows-latest.msi / .exe
  • macOS Intelmacos-15-intel,x86_64 .dmg
  • macOS Apple Siliconmacos-latest,aarch64 .dmg

Linux 说明:workflow 里其实也配置了 ubuntu-22.04.deb / .AppImage 任务,但目前该 job 在上游 libspa 0.9.2 crate 编译失败(对现代 rustc 的 bindgen 输出有 bug,见 nashaofu/xcap issue #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-devlibgbm-devlibx11-devlibxtst-devlibxcb-cursor0libxcb-cursor-dev,Linux 构建不再因为缺系统库翻车。
  • vite build 之后断言 dist/picker.html 存在 —— 取色器窗口的 bundle 不再会「莫名消失」。

内部细节

  • order.json 持久化调色板顺序,重启后保留;引用了已删除 palette 时自动愈合。
  • 引入 vitest + jsdom,并为 formatreorder 写了冒烟测试。
  • 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. / 首个公开发布。