@hicccc77/electron-liquid-glass 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,70 +1,70 @@
1
1
  # Electron-Liquid-Glass
2
2
 
3
- Windows 全局原生低延迟「液态玻璃」背景面板,for Electron。
3
+ English | [简体中文](README.zh-CN.md)
4
4
 
5
- Low-latency native liquid glass backdrop panels for Electron apps, powered by DXGI Desktop Duplication + D3D11 + DirectComposition.
5
+ Low-latency native "liquid glass" backdrop panels for Electron apps on Windows, powered by DXGI Desktop Duplication + D3D11 + DirectComposition.
6
6
 
7
- 把液态玻璃渲染为一个全局独立的原生窗口,放在你的 Electron 窗口正下方作为实时背景层。
7
+ The liquid glass effect is rendered as a standalone native window pinned right below your Electron window, acting as a live refractive background layer.
8
8
 
9
- ![真实渲染效果:Electron 通知窗口(内容层)+ 原生玻璃面板(折射层)](https://raw.githubusercontent.com/hicccc77/electron-liquid-glass/main/docs/demo.png)
9
+ ![Real render: Electron notification window (content layer) + native glass panel (refraction layer)](https://raw.githubusercontent.com/hicccc77/electron-liquid-glass/main/docs/demo.png)
10
10
 
11
- > 真实渲染截图(非合成图):通知卡片为 Electron 透明窗口,卡片背后的折射、模糊、色散与驱动文字反色的亮度采样全部来自本模块的原生面板。
11
+ > Real screenshot, not a mockup: the notification card is a transparent Electron window; the refraction, blur, chromatic aberration behind it — and the luminance sampling that drives the adaptive text color — all come from this module's native panel.
12
12
 
13
- ## 特性
13
+ ## Features
14
14
 
15
- - **真折射,非毛玻璃**:圆角矩形 SDF 透镜位移,边缘可见清晰的背景折射与色散,中心通透
16
- - **6ms 级响应**:DXGI 零拷贝拿 GPU 桌面纹理,D3D11 渲染,DirectComposition 直接上屏,全程不落 CPU
17
- - **深度节能**:全链路事件驱动 + 增量——桌面不动不画、脏区与面板不相交不画、桌面镜像按脏区增量维护(GPU 拷贝量正比实际变化面积而非全屏)、自家面板 Present 产生的 DWM 回声脏区被识别丢弃(不会自激重绘)、无面板自动休眠释放采集会话
18
- - **自适应反色支持**:内置亮度带采样(均值色 + luma p15/p85),重绘驱动、与画面同帧推送(上限 ~60Hz),驱动上层文字明暗自适应
19
- - **z 序锚定**:面板自动钉在指定 Electron 窗口正下方,并周期性重申(防其他置顶窗口插队)
20
- - **防自采集回环**:`WDA_EXCLUDEFROMCAPTURE` 把面板从一切屏幕捕获中排除
21
- - **零 Electron 侵入**:纯 N-API 原生模块 + 命令队列,跨 Electron 版本 ABI 稳定,任何 Electron 应用可直接接入
15
+ - **True refraction, not frosted glass**: rounded-rect SDF lens displacement with visible edge refraction and chromatic aberration, crystal-clear center
16
+ - **~6ms response**: zero-copy GPU desktop texture via DXGI, D3D11 shading, DirectComposition presentation — pixels never touch the CPU
17
+ - **Deeply energy-efficient**: fully event-driven and incremental — no repaint when the desktop is static, no repaint when dirty regions don't intersect the panel, the desktop mirror is maintained incrementally from dirty rects (GPU copy volume proportional to actual changed area, not full screen), DWM "echo" dirty rects caused by the panel's own Present are detected and dropped (no self-sustained repaint loop), and the capture session is released when no panel is visible
18
+ - **Adaptive contrast support**: built-in luminance band sampling (mean color + luma p15/p85), repaint-driven and pushed in the same frame as the visual change (capped at ~60Hz), for driving light/dark adaptive text above the glass
19
+ - **Z-order anchoring**: the panel pins itself directly below a given Electron window and periodically re-asserts the order (defends against other topmost windows cutting in)
20
+ - **Self-capture loop prevention**: `WDA_EXCLUDEFROMCAPTURE` excludes the panel from all screen capture
21
+ - **Zero Electron intrusion**: pure N-API native module + command queue, ABI-stable across Electron versions, drops into any Electron app
22
22
 
23
- ## 原理
23
+ ## How it works
24
24
 
25
25
  ```
26
- DXGI Desktop Duplication(零拷贝 GPU 桌面纹理,仅画面变化时出帧)
27
- → D3D11 三趟着色(半分辨率可分离高斯模糊 ×2 → 圆角 SDF 透镜位移 + RGB 色散 + 饱和度 + 圆角 AA
28
- → DirectComposition 预乘 alpha 交换链直接上屏(不经过 DWM 重定向位图)
26
+ DXGI Desktop Duplication (zero-copy GPU desktop texture; frames arrive only when the screen changes)
27
+ → D3D11 three-pass shading (half-res separable Gaussian blur ×2 → rounded-rect SDF lens displacement + RGB dispersion + saturation + rounded-corner AA)
28
+ → DirectComposition premultiplied-alpha swapchain presentation (bypasses the DWM redirection bitmap)
29
29
  ```
30
30
 
31
- - 全链路在一个独立工作线程 + GPU 上完成,无像素跨进程/跨线程拷贝
32
- - 面板窗口 `WS_EX_NOREDIRECTIONBITMAP + WS_EX_TRANSPARENT + WS_EX_NOACTIVATE`(鼠标穿透、不抢焦点、不进任务栏)
33
- - JS 侧所有调用经命令队列异步投递到工作线程,天然线程安全
34
- - 分层协作:本面板负责「玻璃背后的世界」(折射/模糊/色散),你的 Electron 透明窗口负责「玻璃表面」(文字、高光、描边、tint
31
+ - The whole chain runs on one dedicated worker thread + the GPU; no pixels cross processes or threads
32
+ - Panel window uses `WS_EX_NOREDIRECTIONBITMAP + WS_EX_TRANSPARENT + WS_EX_NOACTIVATE` (click-through, never steals focus, not in the taskbar)
33
+ - Every JS call is posted asynchronously to the worker thread via a command queue — inherently thread-safe
34
+ - Layered collaboration: this panel renders "the world behind the glass" (refraction/blur/dispersion); your transparent Electron window renders "the glass surface" (text, highlights, borders, tint)
35
35
 
36
36
  ```
37
- ┌─ Electron 透明窗口(内容层:文字 / 高光 / 边框)─┐你的应用
38
- │ ┌─ 原生玻璃面板(折射层,钉在正下方)────────┐ │ ← 本模块
39
- │ │ 实时折射的桌面背景 │ │
40
- └──┴────────────────────────────────────────────┴──┘
37
+ ┌─ Electron transparent window (content: text / highlight / border) ─┐your app
38
+ │ ┌─ Native glass panel (refraction layer, pinned right below) ──┐ │ ← this module
39
+ │ │ live refracted desktop background │ │
40
+ └──┴──────────────────────────────────────────────────────────────┴──┘
41
41
  ```
42
42
 
43
- ## 系统要求
43
+ ## Requirements
44
44
 
45
- | 平台 | 支持状态 |
45
+ | Platform | Status |
46
46
  |---|---|
47
- | Windows 10 2004 (build 19041)+ | 完整支持 |
48
- | Windows 更旧版本 | `isSupported()` 返回 `false`(缺少 `WDA_EXCLUDEFROMCAPTURE`) |
49
- | macOS / Linux | 模块可正常安装加载,`isSupported()` 返回 `false`,请回退到你自己的方案(如 Chromium 桌面流 + WebGL);macOS 原生后端(ScreenCaptureKit + Metal)在路线图中 |
47
+ | Windows 10 2004 (build 19041)+ | Fully supported |
48
+ | Older Windows | `isSupported()` returns `false` (no `WDA_EXCLUDEFROMCAPTURE`) |
49
+ | macOS / Linux | Installs and loads fine, `isSupported()` returns `false` — fall back to your own approach (e.g. Chromium desktop capture + WebGL); a native macOS backend (ScreenCaptureKit + Metal) is on the roadmap |
50
50
 
51
- ## 安装
51
+ ## Install
52
52
 
53
53
  ```bash
54
54
  npm install @hicccc77/electron-liquid-glass
55
55
  ```
56
56
 
57
- npm 包内置 win32-x64 预编译二进制(N-API 8,跨 Electron / Node 版本 ABI 稳定),**安装零编译、无需任何构建工具链**;非 Windows 平台上没有预编译产物时模块自动降级(`isSupported()` 返回 `false`),同样不触发编译。
57
+ The npm package ships a prebuilt win32-x64 binary (N-API 8, ABI-stable across Electron / Node versions) **zero compilation on install, no build toolchain required**. On platforms without a prebuild (macOS/Linux) the module degrades gracefully (`isSupported()` returns `false`) and still never triggers a compile.
58
58
 
59
- Electron 打包(electron-builder)注意把 `.node` 解包出 asar
59
+ When packaging with electron-builder, unpack the `.node` binary from asar:
60
60
 
61
61
  ```jsonc
62
62
  "build": { "asarUnpack": ["node_modules/@hicccc77/electron-liquid-glass/**/*"] }
63
63
  ```
64
64
 
65
- 从源码构建(仓库检出,Windows):需要 Node.js 18+、VS Build ToolsC++ 桌面工作负载)+ Python,`npm run build` 产出 `build/Release`,`npm run prebuilds` 产出随包分发的 `prebuilds/win32-x64`。
65
+ Building from source (repo checkout, Windows): Node.js 18+, VS Build Tools (C++ desktop workload) + Python. `npm run build` produces `build/Release`; `npm run prebuilds` produces the distributable `prebuilds/win32-x64`.
66
66
 
67
- ## 快速上手(Electron 主进程)
67
+ ## Quick start (Electron main process)
68
68
 
69
69
  ```js
70
70
  const { screen } = require('electron')
@@ -73,95 +73,85 @@ const glass = require('@hicccc77/electron-liquid-glass')
73
73
  if (glass.isSupported()) {
74
74
  const dpr = screen.getPrimaryDisplay().scaleFactor
75
75
  const panel = glass.createPanel({
76
- // 屏幕物理像素
76
+ // screen physical pixels
77
77
  x: 1560, y: 40, width: 344, height: 96,
78
78
  cornerRadius: 20, blurSigma: 5,
79
79
  displacementScale: 70, aberrationIntensity: 2, saturation: 1.4,
80
80
  dpr,
81
- anchorWindow: myToastWindow, // 面板钉在该 BrowserWindow 正下方
82
- lumaBands: [ // 自适应反色的亮度采样带(面板本地物理像素)
81
+ anchorWindow: myToastWindow, // pin the panel right below this BrowserWindow
82
+ lumaBands: [ // luminance bands for adaptive text contrast (panel-local physical px)
83
83
  { id: 0, x: 0, y: 0, width: 344, height: 48 },
84
84
  { id: 1, x: 0, y: 48, width: 344, height: 48 }
85
85
  ],
86
86
  onLuma: bands => {
87
87
  // bands = { '0': { r, g, b, darkTail, lightTail }, '1': ... }
88
- // 均值 RGB + luma p15/p85gamma 0~255)。重绘驱动:
89
- // 背景变化的同一帧推送(上限 ~60Hz),桌面静止时不推送
90
- // 据此切换上层文字的明暗配色
88
+ // Mean RGB + luma p15/p85 (gamma domain, 0-255). Repaint-driven:
89
+ // pushed in the same frame the background changes (capped ~60Hz),
90
+ // nothing is pushed while the desktop is static.
91
+ // Use it to switch your text between light/dark styles.
91
92
  }
92
93
  })
93
94
 
94
- panel.show(120) // 淡入 120ms
95
- panel.setBounds({ x, y, width, height }) // 跟随窗口移动/改尺寸
96
- panel.hide(240) // 淡出
95
+ panel.show(120) // fade in over 120ms
96
+ panel.setBounds({ x, y, width, height }) // follow window moves/resizes
97
+ panel.hide(240) // fade out
97
98
  panel.destroy()
98
99
  } else {
99
- // 回退:Chromium 桌面流 + WebGL 折射管线,或静态 backdrop-filter
100
+ // Fallback: Chromium desktop stream + WebGL refraction pipeline, or a static backdrop-filter
100
101
  }
101
102
  ```
102
103
 
103
- 上层窗口只需把玻璃区域留透明(Electron `transparent: true` 天然满足),自己绘制文字/描边/高光/tint 等内容层,折射背景由本面板提供。
104
+ Your top window only needs to keep the glass area transparent (Electron `transparent: true` already does) and draw the content layer — text, borders, highlights, tint. The refracted background comes from this panel.
104
105
 
105
106
  ## API
106
107
 
107
- 完整类型见 [`index.d.ts`](index.d.ts)。所有面板方法线程安全。
108
+ Full types in [`index.d.ts`](index.d.ts). All panel methods are thread-safe.
108
109
 
109
- | 方法 | 说明 |
110
+ | Method | Description |
110
111
  |---|---|
111
- | `isSupported()` | 当前环境是否可用(Windows 10 2004+ 且原生二进制已构建) |
112
- | `createPanel(options)` | 创建面板,返回句柄;不可用时返回 `null` |
113
- | `panel.show(fadeMs?)` / `panel.hide(fadeMs?)` | 淡入 / 淡出(`0` = 立即) |
114
- | `panel.setBounds(bounds)` | 移动 / 改尺寸(物理像素) |
115
- | `panel.setParams(params)` | 更新视觉参数(圆角、模糊、位移、色散、饱和度) |
116
- | `panel.anchor(windowOrHwnd)` | 重新钉到某窗口正下方(接受 `BrowserWindow` HWND Buffer |
117
- | `panel.setLumaBands(bands)` / `panel.onLuma(cb)` | 更新亮度采样带 / 回调 |
118
- | `panel.destroy()` | 销毁面板 |
119
- | `shutdown()` | 停止工作线程并销毁所有面板 |
120
-
121
- ## 实测(1080p,动态背景,Windows 11
122
-
123
- | 指标 | Chromium 流方案(getUserMedia + WebGL | 本模块 |
112
+ | `isSupported()` | Whether the current environment is supported (Windows 10 2004+ with a native binary available) |
113
+ | `createPanel(options)` | Create a panel, returns a handle; returns `null` when unsupported |
114
+ | `panel.show(fadeMs?)` / `panel.hide(fadeMs?)` | Fade in / out (`0` = immediate) |
115
+ | `panel.setBounds(bounds)` | Move / resize (physical pixels) |
116
+ | `panel.setParams(params)` | Update visual params (corner radius, blur, displacement, aberration, saturation) |
117
+ | `panel.anchor(windowOrHwnd)` | Re-pin below a window (accepts `BrowserWindow` or an HWND Buffer) |
118
+ | `panel.setLumaBands(bands)` / `panel.onLuma(cb)` | Update luminance bands / callback |
119
+ | `panel.destroy()` | Destroy the panel |
120
+ | `shutdown()` | Stop the worker thread and destroy all panels |
121
+
122
+ ## Measured results (1080p, animated background, Windows 11)
123
+
124
+ | Metric | Chromium stream approach (getUserMedia + WebGL) | This module |
124
125
  |---|---|---|
125
- | 感知位置滞后(中位 / p90 | 77ms / 89ms | **6ms / 6ms** |
126
- | 满载 CPU 增量(主+GPU+渲染进程合计) | ~1.5% | **~0.3%** |
127
- | 静止桌面开销 | 持续采集出帧 | **0 渲染 / 0 拷贝**(事件驱动) |
128
- | 首帧启动 | ~80-300msgetUserMedia 协商) | **<150ms**(面板常驻复用后为 0 |
129
- | 40 轮通知压测 | — | 面板 1 81 复用,内存零增长,零异常 |
126
+ | Perceived position lag (median / p90) | 77ms / 89ms | **6ms / 6ms** |
127
+ | CPU delta under load (main + GPU + renderer processes) | ~1.5% | **~0.3%** |
128
+ | Static desktop overhead | continuous capture frames | **0 renders / 0 copies** (event-driven) |
129
+ | First-frame startup | ~80-300ms (getUserMedia negotiation) | **<150ms** (0 when a persistent panel is reused) |
130
+ | 40-round notification stress | — | 1 panel created, 81 reuses, zero memory growth, zero errors |
130
131
 
131
- 测量方法:同帧差分法——同一帧屏幕采集内对比玻璃呈现内容与背景真值条纹的计数差,两个时间戳均来自绘制时刻,结果与探针自身延迟无关。
132
+ Measurement method: same-frame differencing — within a single captured frame, compare the counter stripes shown through the glass against the ground-truth stripes in the background; both timestamps come from draw time, so probe latency cancels out.
132
133
 
133
- ### v0.2.0 能耗优化(内部计数器实测,1080p@180Hz 压力场景)
134
134
 
135
- | 场景 | v0.1.x | v0.2.0 |
136
- |---|---|---|
137
- | 桌面静止时的面板重绘 | 178 次/秒(Present 回声自激) | **0** |
138
- | 桌面静止时的镜像拷贝带宽 | 1421 MB/s(每帧全屏) | **3.5 MB/s**(406×) |
139
- | 无关区域动画时的面板重绘 | 179 次/秒 | **0**(脏区不相交不画) |
140
- | 无关区域动画时的拷贝带宽 | 1423 MB/s | **350 MB/s**(正比脏区面积) |
141
- | 亮度采样 GPU 同步停顿 | 458 µs/次 | **2.3 µs/次**(延后一拍读取) |
142
-
143
- 三项根因修复:① 被 `WDA_EXCLUDEFROMCAPTURE` 排除的面板自身 Present 后,DWM 仍会把面板矩形报告为 DDA 脏区(内容实际未变),形成「重绘→报脏→再重绘」自激循环,现按矩形近似相等识别并丢弃回声脏区;② 桌面镜像从每帧全屏 `CopyResource` 改为脏区包围盒增量拷贝;③ 亮度带 staging 回读从渲染同 tick 的立即 `Map`(强制等 GPU 跑完整条管线)改为下一 tick 读取上帧拷贝,等待归零且时效不变(≤8ms)。
144
-
145
- ## 源码结构
135
+ ## Source layout
146
136
 
147
137
  ```
148
138
  src/
149
- ├── addon.cc N-API 绑定层(参数解析、亮度回调线程安全投递)
150
- ├── session.cc/h 调度中枢:独占工作线程跑「采集→渲染→上屏」闭环、命令队列、节能策略
151
- ├── capture.cc/h DXGI Desktop Duplication 采集(零拷贝 GPU 纹理 + 脏区 + 自回声过滤)
152
- ├── renderer.cc/h D3D11 三趟玻璃管线 + 亮度带直方图采样
153
- ├── panel.cc/h DirectComposition 无重定向位图窗口、淡入淡出、z 序锚定、捕获排除
154
- ├── d3d_utils.cc/h 设备创建辅助
155
- ├── stats.h 内部性能计数器(`_stats` 诊断导出,基准测试用)
156
- └── addon_stub.cc Windows 桩(isSupported() = false
139
+ ├── addon.cc N-API binding layer (argument parsing, thread-safe luma callback dispatch)
140
+ ├── session.cc/h Scheduler: dedicated worker thread running the capture→render→present loop, command queue, energy policies
141
+ ├── capture.cc/h DXGI Desktop Duplication capture (zero-copy GPU texture + dirty regions + self-echo filtering)
142
+ ├── renderer.cc/h D3D11 three-pass glass pipeline + luminance band histogram sampling
143
+ ├── panel.cc/h DirectComposition no-redirection-bitmap window, fades, z-order anchoring, capture exclusion
144
+ ├── d3d_utils.cc/h Device creation helper
145
+ ├── stats.h Internal performance counters (`_stats` diagnostic export, used by benchmarks)
146
+ └── addon_stub.cc Non-Windows stub (isSupported() = false)
157
147
  ```
158
148
 
159
- ## 已知限制
149
+ ## Known limitations
160
150
 
161
- - 目前仅 Windows 有原生实现(macOS ScreenCaptureKit + Metal 后端在路线图中,API 已按平台后端可插拔设计)
162
- - 面板排除于截屏/录屏(`WDA_EXCLUDEFROMCAPTURE` 的语义,与内容保护窗口一致)
163
- - 安全桌面(UAC / 锁屏)期间采集暂停,返回后自动恢复
164
- - 多显示器:采集会话跟随首个可见面板所在显示器;跨屏移动面板会自动重建会话
151
+ - Native implementation is Windows-only for now (macOS ScreenCaptureKit + Metal backend is on the roadmap; the API is designed for pluggable per-platform backends)
152
+ - The panel is excluded from screenshots/recordings (the semantics of `WDA_EXCLUDEFROMCAPTURE`, same as content-protected windows)
153
+ - Capture pauses during secure desktop (UAC / lock screen) and resumes automatically afterwards
154
+ - Multi-monitor: the capture session follows the display of the first visible panel; moving a panel across displays rebuilds the session automatically
165
155
 
166
156
  ## License
167
157
 
@@ -0,0 +1,157 @@
1
+ # Electron-Liquid-Glass
2
+
3
+ [English](README.md) | 简体中文
4
+
5
+ Windows 全局原生低延迟「液态玻璃」背景面板,for Electron。基于 DXGI Desktop Duplication + D3D11 + DirectComposition。
6
+
7
+ 把液态玻璃渲染为一个全局独立的原生窗口,放在你的 Electron 窗口正下方作为实时背景层。
8
+
9
+ ![真实渲染效果:Electron 通知窗口(内容层)+ 原生玻璃面板(折射层)](https://raw.githubusercontent.com/hicccc77/electron-liquid-glass/main/docs/demo.png)
10
+
11
+ > 真实渲染截图:通知卡片为 Electron 透明窗口,卡片背后的折射、模糊、色散与驱动文字反色的亮度采样全部来自本模块的原生面板。
12
+
13
+ ## 特性
14
+
15
+ - **物理折射效果**:圆角矩形 SDF 透镜位移,边缘可见清晰的背景折射与色散,中心通透
16
+ - **6ms 级响应**:DXGI 零拷贝拿 GPU 桌面纹理,D3D11 渲染,DirectComposition 直接渲染上屏幕
17
+ - **深度节能**:全链路事件驱动 + 增量——桌面不动不画、脏区与面板不相交不画、桌面镜像按脏区增量维护(GPU 拷贝量正比实际变化面积而非全屏)、自家面板 Present 产生的 DWM 回声脏区被识别丢弃(不会自激重绘)、无面板自动休眠释放采集会话
18
+ - **自适应反色支持**:内置亮度带采样(均值色 + luma p15/p85),重绘驱动、与画面同帧推送(上限 ~60Hz),驱动上层文字明暗自适应
19
+ - **z 序锚定**:面板自动钉在指定 Electron 窗口正下方,并周期性重申(防其他置顶窗口插队)
20
+ - **防自采集回环**:`WDA_EXCLUDEFROMCAPTURE` 把面板从一切屏幕捕获中排除
21
+ - **零 Electron 侵入**:纯 N-API 原生模块 + 命令队列,跨 Electron 版本 ABI 稳定,任何 Electron 应用可直接接入
22
+
23
+ ## 原理
24
+
25
+ ```
26
+ DXGI Desktop Duplication(零拷贝 GPU 桌面纹理,仅画面变化时出帧)
27
+ → D3D11 三趟着色(半分辨率可分离高斯模糊 ×2 → 圆角 SDF 透镜位移 + RGB 色散 + 饱和度 + 圆角 AA)
28
+ → DirectComposition 预乘 alpha 交换链直接上屏(不经过 DWM 重定向位图)
29
+ ```
30
+
31
+ - 全链路在一个独立工作线程 + GPU 上完成,无像素跨进程/跨线程拷贝
32
+ - 面板窗口 `WS_EX_NOREDIRECTIONBITMAP + WS_EX_TRANSPARENT + WS_EX_NOACTIVATE`(鼠标穿透、不抢焦点、不进任务栏)
33
+ - JS 侧所有调用经命令队列异步投递到工作线程,天然线程安全
34
+ - 分层协作:本面板负责「玻璃背后的世界」(折射/模糊/色散),你的 Electron 透明窗口负责「玻璃表面」(文字、高光、描边、tint)
35
+
36
+ ```
37
+ ┌─ Electron 透明窗口(内容层:文字 / 高光 / 边框)─┐ ← 你的应用
38
+ │ ┌─ 原生玻璃面板(折射层,钉在正下方)────────┐ │ ← 本模块
39
+ │ │ 实时折射的桌面背景 │ │
40
+ └──┴────────────────────────────────────────────┴──┘
41
+ ```
42
+
43
+ ## 系统要求
44
+
45
+ | 平台 | 支持状态 |
46
+ |---|---|
47
+ | Windows 10 2004 (build 19041)+ | 完整支持 |
48
+ | Windows 更旧版本 | `isSupported()` 返回 `false`(缺少 `WDA_EXCLUDEFROMCAPTURE`) |
49
+ | macOS / Linux | 模块可正常安装加载,`isSupported()` 返回 `false`,请回退到你自己的方案(如 Chromium 桌面流 + WebGL);macOS 原生后端(ScreenCaptureKit + Metal)在路线图中 |
50
+
51
+ ## 安装
52
+
53
+ ```bash
54
+ npm install @hicccc77/electron-liquid-glass
55
+ ```
56
+
57
+ npm 包内置 win32-x64 预编译二进制(N-API 8,跨 Electron / Node 版本 ABI 稳定),**安装零编译、无需任何构建工具链**;非 Windows 平台上没有预编译产物时模块自动降级(`isSupported()` 返回 `false`),同样不触发编译。
58
+
59
+ Electron 打包(electron-builder)注意把 `.node` 解包出 asar:
60
+
61
+ ```jsonc
62
+ "build": { "asarUnpack": ["node_modules/@hicccc77/electron-liquid-glass/**/*"] }
63
+ ```
64
+
65
+ 从源码构建(仓库检出,Windows):需要 Node.js 18+、VS Build Tools(C++ 桌面工作负载)+ Python,`npm run build` 产出 `build/Release`,`npm run prebuilds` 产出随包分发的 `prebuilds/win32-x64`。
66
+
67
+ ## 快速上手(Electron 主进程)
68
+
69
+ ```js
70
+ const { screen } = require('electron')
71
+ const glass = require('@hicccc77/electron-liquid-glass')
72
+
73
+ if (glass.isSupported()) {
74
+ const dpr = screen.getPrimaryDisplay().scaleFactor
75
+ const panel = glass.createPanel({
76
+ // 屏幕物理像素
77
+ x: 1560, y: 40, width: 344, height: 96,
78
+ cornerRadius: 20, blurSigma: 5,
79
+ displacementScale: 70, aberrationIntensity: 2, saturation: 1.4,
80
+ dpr,
81
+ anchorWindow: myToastWindow, // 面板钉在该 BrowserWindow 正下方
82
+ lumaBands: [ // 自适应反色的亮度采样带(面板本地物理像素)
83
+ { id: 0, x: 0, y: 0, width: 344, height: 48 },
84
+ { id: 1, x: 0, y: 48, width: 344, height: 48 }
85
+ ],
86
+ onLuma: bands => {
87
+ // bands = { '0': { r, g, b, darkTail, lightTail }, '1': ... }
88
+ // 均值 RGB + luma p15/p85(gamma 域 0~255)。重绘驱动:
89
+ // 背景变化的同一帧推送(上限 ~60Hz),桌面静止时不推送
90
+ // 据此切换上层文字的明暗配色
91
+ }
92
+ })
93
+
94
+ panel.show(120) // 淡入 120ms
95
+ panel.setBounds({ x, y, width, height }) // 跟随窗口移动/改尺寸
96
+ panel.hide(240) // 淡出
97
+ panel.destroy()
98
+ } else {
99
+ // 回退:Chromium 桌面流 + WebGL 折射管线,或静态 backdrop-filter
100
+ }
101
+ ```
102
+
103
+ 上层窗口只需把玻璃区域留透明(Electron `transparent: true` 天然满足),自己绘制文字/描边/高光/tint 等内容层,折射背景由本面板提供。
104
+
105
+ ## API
106
+
107
+ 完整类型见 [`index.d.ts`](index.d.ts)。所有面板方法线程安全。
108
+
109
+ | 方法 | 说明 |
110
+ |---|---|
111
+ | `isSupported()` | 当前环境是否可用(Windows 10 2004+ 且原生二进制已构建) |
112
+ | `createPanel(options)` | 创建面板,返回句柄;不可用时返回 `null` |
113
+ | `panel.show(fadeMs?)` / `panel.hide(fadeMs?)` | 淡入 / 淡出(`0` = 立即) |
114
+ | `panel.setBounds(bounds)` | 移动 / 改尺寸(物理像素) |
115
+ | `panel.setParams(params)` | 更新视觉参数(圆角、模糊、位移、色散、饱和度) |
116
+ | `panel.anchor(windowOrHwnd)` | 重新钉到某窗口正下方(接受 `BrowserWindow` 或 HWND Buffer) |
117
+ | `panel.setLumaBands(bands)` / `panel.onLuma(cb)` | 更新亮度采样带 / 回调 |
118
+ | `panel.destroy()` | 销毁面板 |
119
+ | `shutdown()` | 停止工作线程并销毁所有面板 |
120
+
121
+ ## 实测(1080p,动态背景,Windows 11)
122
+
123
+ | 指标 | Chromium 流方案(getUserMedia + WebGL) | 本模块 |
124
+ |---|---|---|
125
+ | 感知位置滞后(中位 / p90) | 77ms / 89ms | **6ms / 6ms** |
126
+ | 满载 CPU 增量(主+GPU+渲染进程合计) | ~1.5% | **~0.3%** |
127
+ | 静止桌面开销 | 持续采集出帧 | **0 渲染 / 0 拷贝**(事件驱动) |
128
+ | 首帧启动 | ~80-300ms(getUserMedia 协商) | **<150ms**(面板常驻复用后为 0) |
129
+ | 40 轮通知压测 | — | 面板 1 建 81 复用,内存零增长,零异常 |
130
+
131
+ 测量方法:同帧差分法——同一帧屏幕采集内对比玻璃呈现内容与背景真值条纹的计数差,两个时间戳均来自绘制时刻,结果与探针自身延迟无关。
132
+
133
+
134
+ ## 源码结构
135
+
136
+ ```
137
+ src/
138
+ ├── addon.cc N-API 绑定层(参数解析、亮度回调线程安全投递)
139
+ ├── session.cc/h 调度中枢:独占工作线程跑「采集→渲染→上屏」闭环、命令队列、节能策略
140
+ ├── capture.cc/h DXGI Desktop Duplication 采集(零拷贝 GPU 纹理 + 脏区 + 自回声过滤)
141
+ ├── renderer.cc/h D3D11 三趟玻璃管线 + 亮度带直方图采样
142
+ ├── panel.cc/h DirectComposition 无重定向位图窗口、淡入淡出、z 序锚定、捕获排除
143
+ ├── d3d_utils.cc/h 设备创建辅助
144
+ ├── stats.h 内部性能计数器(`_stats` 诊断导出,基准测试用)
145
+ └── addon_stub.cc 非 Windows 桩(isSupported() = false)
146
+ ```
147
+
148
+ ## 已知限制
149
+
150
+ - 目前仅 Windows 有原生实现(macOS ScreenCaptureKit + Metal 后端在路线图中,API 已按平台后端可插拔设计)
151
+ - 面板排除于截屏/录屏(`WDA_EXCLUDEFROMCAPTURE` 的语义,与内容保护窗口一致)
152
+ - 安全桌面(UAC / 锁屏)期间采集暂停,返回后自动恢复
153
+ - 多显示器:采集会话跟随首个可见面板所在显示器;跨屏移动面板会自动重建会话
154
+
155
+ ## License
156
+
157
+ [MIT](LICENSE)
package/index.d.ts CHANGED
@@ -1,31 +1,33 @@
1
1
  /**
2
2
  * electron-liquid-glass
3
- * Windows 原生低延迟液态玻璃背景面板(DXGI Desktop Duplication + D3D11 + DirectComposition)
3
+ * Low-latency native liquid glass backdrop panels for Windows
4
+ * (DXGI Desktop Duplication + D3D11 + DirectComposition).
4
5
  *
5
- * 所有坐标与尺寸均为屏幕物理像素。
6
+ * All coordinates and sizes are screen physical pixels.
6
7
  */
7
8
 
8
- /** 玻璃视觉参数(长度单位:物理像素) */
9
+ /** Glass visual parameters (lengths in physical pixels) */
9
10
  export interface GlassEffectParams {
10
- /** 圆角半径,默认 20 */
11
+ /** Corner radius, default 20 */
11
12
  cornerRadius?: number
12
- /** 高斯模糊σ,默认 5 */
13
+ /** Gaussian blur sigma, default 5 */
13
14
  blurSigma?: number
14
- /** 边缘位移强度(70 = 标准强度),默认 70 */
15
+ /** Edge displacement strength (70 = standard), default 70 */
15
16
  displacementScale?: number
16
- /** RGB 色散强度(0~3),默认 2 */
17
+ /** RGB chromatic aberration strength (0-3), default 2 */
17
18
  aberrationIntensity?: number
18
- /** 饱和度增益,默认 1.4 */
19
+ /** Saturation gain, default 1.4 */
19
20
  saturation?: number
20
21
  /**
21
- * 采样区相对面板的偏移。常规玻璃保持 0
22
- * 0 时面板折射别处内容(测量/特效场景)
22
+ * Offset of the sampled area relative to the panel. Keep 0 for regular
23
+ * glass; non-zero makes the panel refract content from elsewhere
24
+ * (measurement / special-effect scenarios).
23
25
  */
24
26
  sourceOffsetX?: number
25
27
  sourceOffsetY?: number
26
28
  }
27
29
 
28
- /** 亮度采样带(矩形为面板本地物理像素) */
30
+ /** Luminance sampling band (rect in panel-local physical pixels) */
29
31
  export interface LumaBand {
30
32
  id: number
31
33
  x: number
@@ -34,7 +36,7 @@ export interface LumaBand {
34
36
  height: number
35
37
  }
36
38
 
37
- /** 亮度带统计:玻璃模糊层的均值色 + luma p15/p850~255 */
39
+ /** Band statistics: mean color of the blurred glass layer + luma p15/p85 (0-255) */
38
40
  export interface LumaBandStats {
39
41
  r: number
40
42
  g: number
@@ -48,44 +50,46 @@ export interface CreatePanelOptions extends GlassEffectParams {
48
50
  y: number
49
51
  width: number
50
52
  height: number
51
- /** 显示器缩放系数(内部几何常量按此缩放),默认 1 */
53
+ /** Display scale factor (internal geometry constants scale by it), default 1 */
52
54
  dpr?: number
53
55
  /**
54
- * 从屏幕捕获(截屏/录屏/DDA/WGC)中排除面板,默认 true。
55
- * 必须保持 true 才能避免自采集反馈回路;仅测试可关。
56
+ * Exclude the panel from screen capture (screenshots/recording/DDA/WGC),
57
+ * default true. Must stay true to avoid self-capture feedback loops;
58
+ * disable only for testing.
56
59
  */
57
60
  excludeFromCapture?: boolean
58
- /** 把面板 z 序钉在该窗口正下方(Electron BrowserWindow HWND Buffer */
61
+ /** Pin the panel's z-order right below this window (Electron BrowserWindow or HWND Buffer) */
59
62
  anchorWindow?: unknown
60
- /** 亮度采样带(配合 onLuma 做自适应文字反色) */
63
+ /** Luminance sampling bands (pair with onLuma for adaptive text contrast) */
61
64
  lumaBands?: LumaBand[]
62
65
  /**
63
- * 亮度回调:bands { [bandId]: LumaBandStats }
64
- * 重绘驱动:面板下方内容变化的同一帧推送(上限 ~60Hz),桌面静止时不推送
66
+ * Luminance callback: bands is { [bandId]: LumaBandStats }.
67
+ * Repaint-driven: pushed in the same frame the content under the panel
68
+ * changes (capped at ~60Hz); nothing is pushed while the desktop is static.
65
69
  */
66
70
  onLuma?: (bands: Record<string, LumaBandStats>) => void
67
71
  }
68
72
 
69
73
  export interface GlassPanel {
70
74
  readonly id: number
71
- /** 显示并淡入(默认 120ms */
75
+ /** Show with fade-in (default 120ms) */
72
76
  show(fadeMs?: number): void
73
- /** 淡出并隐藏(默认 100ms0 = 立即) */
77
+ /** Fade out and hide (default 100ms; 0 = immediate) */
74
78
  hide(fadeMs?: number): void
75
79
  destroy(): void
76
80
  setBounds(bounds: { x: number; y: number; width: number; height: number }): void
77
- /** 更新视觉参数(传完整参数对象,缺省字段回落默认值) */
81
+ /** Update visual parameters (pass the full object; omitted fields fall back to defaults) */
78
82
  setParams(params: GlassEffectParams): void
79
83
  anchor(windowOrHwnd: unknown): void
80
84
  setLumaBands(bands: LumaBand[]): void
81
85
  onLuma(cb: (bands: Record<string, LumaBandStats>) => void): void
82
86
  }
83
87
 
84
- /** 当前环境是否支持原生玻璃(Windows 10 2004+ 且原生二进制已构建) */
88
+ /** Whether native glass is supported here (Windows 10 2004+ with a native binary available) */
85
89
  export function isSupported(): boolean
86
90
 
87
- /** 创建玻璃面板;原生不可用时返回 null(调用方应回退) */
91
+ /** Create a glass panel; returns null when the native backend is unavailable (callers should fall back) */
88
92
  export function createPanel(options: CreatePanelOptions): GlassPanel | null
89
93
 
90
- /** 停止工作线程并销毁所有面板(进程退出前自动调用) */
94
+ /** Stop the worker thread and destroy all panels (called automatically before process exit) */
91
95
  export function shutdown(): void
package/index.js CHANGED
@@ -1,8 +1,10 @@
1
- // electron-liquid-glass JS 入口:原生模块加载守护 + 面板对象封装。
2
- // node-gyp-build 依次尝试 prebuilds/<platform>-<arch>(npm 分发的预编译产物,
3
- // N-API 8,无需使用者本地编译)与 build/Release(仓库内开发构建)。
4
- // 原生不可用(非 Windows、系统过旧、无预编译产物)时 isSupported() 返回 false,
5
- // 调用方据此回退自己的方案(如 Chromium 屏幕采集管线)。
1
+ // electron-liquid-glass JS entry: guarded native module loading + panel handle wrapper.
2
+ // node-gyp-build tries prebuilds/<platform>-<arch> first (prebuilt binaries shipped
3
+ // on npm, N-API 8, no local compilation for consumers), then build/Release
4
+ // (in-repo development builds).
5
+ // When the native side is unavailable (non-Windows, OS too old, no prebuild),
6
+ // isSupported() returns false and callers should fall back to their own approach
7
+ // (e.g. a Chromium screen-capture pipeline).
6
8
  let native = null
7
9
  try {
8
10
  native = require('node-gyp-build')(__dirname)
@@ -27,8 +29,9 @@ function isSupported() {
27
29
  }
28
30
 
29
31
  /**
30
- * 创建玻璃面板(所有长度均为物理像素;dpr 用于内部几何常量缩放)。
31
- * 返回面板句柄对象;原生不可用时返回 null
32
+ * Create a glass panel (all lengths are physical pixels; dpr scales internal
33
+ * geometry constants). Returns a panel handle object, or null when the native
34
+ * backend is unavailable.
32
35
  */
33
36
  function createPanel(options) {
34
37
  if (!isSupported()) return null
@@ -57,7 +60,7 @@ function createPanel(options) {
57
60
  return panel
58
61
  }
59
62
 
60
- // 接受 Electron BrowserWindow getNativeWindowHandle() 的 Buffer
63
+ // Accepts an Electron BrowserWindow or a Buffer from getNativeWindowHandle()
61
64
  function resolveHwnd(windowOrHwnd) {
62
65
  if (!windowOrHwnd) return null
63
66
  if (Buffer.isBuffer(windowOrHwnd)) return windowOrHwnd
@@ -68,7 +71,7 @@ function resolveHwnd(windowOrHwnd) {
68
71
  }
69
72
 
70
73
  function shutdown() {
71
- // Windows 的桩实现只导出 isSupported/osBuild,其余入口必须判空
74
+ // The non-Windows stub only exports isSupported/osBuild; guard everything else
72
75
  if (native && typeof native.shutdown === 'function') native.shutdown()
73
76
  panels.clear()
74
77
  lumaHooked = false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hicccc77/electron-liquid-glass",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Low-latency native liquid glass backdrop panels for Electron apps (Windows: DXGI Desktop Duplication + D3D11 + DirectComposition)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -48,6 +48,7 @@
48
48
  "prebuilds/",
49
49
  "scripts/install-guard.cjs",
50
50
  "README.md",
51
+ "README.zh-CN.md",
51
52
  "LICENSE"
52
53
  ]
53
54
  }
@@ -1,8 +1,9 @@
1
- // 显式 install 脚本:覆盖 npm 对含 binding.gyp 仓库的隐式 "node-gyp rebuild" 注入。
2
- // npm 分发的 tarball 只带预编译产物(prebuilds/),不含源码与 binding.gyp
3
- // - 命中当前平台的 prebuild:直接通过(零编译)
4
- // - 未命中(如 macOS/Linux):安静降级,运行时 isSupported() 返回 false
5
- // 任何情况下 exit 0,绝不在使用者的 npm install 阶段失败或触发编译
1
+ // Explicit install script: overrides npm's implicit "node-gyp rebuild"
2
+ // injection for repos containing a binding.gyp. The published tarball ships
3
+ // prebuilt binaries only (prebuilds/), no sources and no binding.gyp:
4
+ // - Prebuild matches the current platform: pass through (zero compilation)
5
+ // - No match (e.g. macOS/Linux): degrade quietly; isSupported() returns false at runtime
6
+ // Always exits 0 — never fails or triggers a compile during a consumer's npm install.
6
7
  try {
7
8
  const resolved = require('node-gyp-build').path(require('path').join(__dirname, '..'))
8
9
  console.log('[electron-liquid-glass] prebuild ready:', resolved)