dsh-agent-team-ui-testing 0.0.0-stage → 0.1.2
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/LICENSE +21 -0
- package/README.md +327 -2
- package/annotation-capture.js +111 -0
- package/banner.png +0 -0
- package/banner_zh.png +0 -0
- package/browser-safety.js +293 -0
- package/capture-p0.js +910 -0
- package/client.js +11302 -0
- package/context-menu.js +134 -0
- package/cordis.patch.yml +3 -0
- package/core/clock.js +88 -0
- package/core/config-store.js +566 -0
- package/core/config.js +892 -0
- package/core/contracts.js +240 -0
- package/core/errors.js +156 -0
- package/core/evidence.js +141 -0
- package/core/geometry.js +217 -0
- package/core/identity.js +180 -0
- package/core/index.js +24 -0
- package/core/p0.js +1101 -0
- package/core/readiness.js +175 -0
- package/core/registry.js +239 -0
- package/core/tab-access.js +1350 -0
- package/docs/adapters.md +160 -0
- package/docs/architecture.md +146 -0
- package/docs/capability-tiers.md +80 -0
- package/docs/capture-p0.md +90 -0
- package/docs/diagnose-reason-codes.md +157 -0
- package/docs/element-picker.md +143 -0
- package/docs/getting-started.md +136 -0
- package/docs/index.md +36 -0
- package/docs/multi-tab.md +162 -0
- package/docs/network-p0.md +117 -0
- package/docs/panel-context-menu.md +41 -0
- package/docs/t2-structured-gui.md +68 -0
- package/docs/t3-vision.md +84 -0
- package/docs/t4-dynamic-behavior.md +135 -0
- package/docs/tools.md +174 -0
- package/docs/verification.md +131 -0
- package/docs/viewport-control.md +94 -0
- package/dynamic-t4.js +5699 -0
- package/frame-push.js +508 -0
- package/frame-source.js +162 -0
- package/icon.png +0 -0
- package/index.js +23028 -0
- package/integration/cross-environment.js +1535 -0
- package/integration/diagnose.js +945 -0
- package/integration/tab-principal.js +493 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/network-p0.js +4264 -0
- package/package.json +19 -4
- package/select-control.js +298 -0
- package/skills/ui-testing-common/SKILL.md +54 -0
- package/skills/ui-testing-fake/SKILL.md +43 -0
- package/skills/ui-testing-web/SKILL.md +520 -0
- package/skills/ui-testing-web/manifests/declared-capabilities.json +903 -0
- package/skills/ui-testing-web/references/contracts/capability.md +68 -0
- package/skills/ui-testing-web/references/contracts/evidence.md +41 -0
- package/skills/ui-testing-web/references/contracts/operation.md +44 -0
- package/skills/ui-testing-web/references/core/dynamic-visual.md +123 -0
- package/skills/ui-testing-web/references/core/fallback.md +83 -0
- package/skills/ui-testing-web/references/core/network-and-state.md +114 -0
- package/skills/ui-testing-web/references/core/page-identity.md +91 -0
- package/skills/ui-testing-web/references/core/report-template.md +144 -0
- package/skills/ui-testing-web/references/core/reporting.md +92 -0
- package/skills/ui-testing-web/references/core/safety.md +12 -0
- package/skills/ui-testing-web/references/core/selection.md +26 -0
- package/skills/ui-testing-web/references/core/tool-routing-and-limits.md +198 -0
- package/skills/ui-testing-web/references/core/verdict-examples.md +96 -0
- package/skills/ui-testing-web/references/core/verdict-gate.md +105 -0
- package/skills/ui-testing-web/references/core/verification.md +19 -0
- package/skills/ui-testing-web/references/core/workflow.md +16 -0
- package/skills/ui-testing-web/references/platforms/index.md +19 -0
- package/skills/ui-testing-web/references/platforms/web.md +17 -0
- package/skills/ui-testing-web/references/scenarios/annotations.md +104 -0
- package/skills/ui-testing-web/references/scenarios/functional.md +205 -0
- package/skills/ui-testing-web/references/scenarios/visual-motion.md +170 -0
- package/skills/ui-testing-web/references/tiers/t1-programmatic.md +25 -0
- package/skills/ui-testing-web/references/tiers/t2-structured.md +61 -0
- package/skills/ui-testing-web/references/tiers/t3-static-visual.md +45 -0
- package/skills/ui-testing-web/references/tiers/t4-dynamic-visual.md +58 -0
- package/skills/ui-testing-web/templates/capability-note.md +23 -0
- package/skills/ui-testing-web/templates/platform.md +30 -0
- package/skills/ui-testing-web/templates/regression-case.md +15 -0
- package/skills/ui-testing-web/templates/scenario.md +13 -0
- package/targets/fake/adapter.js +1163 -0
- package/targets/fake/fixtures.js +177 -0
- package/targets/web/adapter.js +1231 -0
- package/targets/web/provider.js +415 -0
- package/vision-baseline.js +1254 -0
- package/vision-t3.js +2657 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bloodarea
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,328 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-agent-team-ui-testing
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="banner.png" alt="dsh-agent-team-ui-testing — multi-platform GUI automation testing for DeepSeekHarness" width="100%">
|
|
4
|
+
|
|
5
|
+
**AI-native frontend GUI testing for DeepSeekHarness.**
|
|
6
|
+
|
|
7
|
+
Let AI agents operate, inspect, test and verify real user interfaces — with evidence humans can review.
|
|
8
|
+
|
|
9
|
+
**English** | [简体中文](README_zh.md)
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
<a href="https://www.npmjs.com/package/dsh-agent-team-ui-testing"><img src="https://img.shields.io/npm/v/dsh-agent-team-ui-testing?style=flat-square&logo=npm&logoColor=white" alt="npm version"></a>
|
|
13
|
+
<a href="https://github.com/bloodarea/dsh-agent-team-ui-testing/stargazers"><img src="https://img.shields.io/github/stars/bloodarea/dsh-agent-team-ui-testing?style=flat-square&logo=github" alt="GitHub stars"></a>
|
|
14
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/bloodarea/dsh-agent-team-ui-testing?style=flat-square" alt="License: MIT"></a>
|
|
15
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 22"></a>
|
|
16
|
+
<a href="docs/getting-started.md"><img src="https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-0078D6?style=flat-square" alt="Platforms"></a>
|
|
17
|
+
<a href="docs/tools.md"><img src="https://img.shields.io/badge/tools-37-brightgreen?style=flat-square" alt="Agent tools"></a>
|
|
18
|
+
<a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/DSH-plugin-4B32C3?style=flat-square" alt="DSH plugin"></a>
|
|
19
|
+
<a href="https://github.com/bloodarea/dsh-agent-team-ui-testing/releases"><img src="https://img.shields.io/badge/status-pre--release-orange?style=flat-square" alt="Status"></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
> **Status: pre-release.** The Web/Chromium channel is implemented across all four tiers: 37 agent tools plus a debug panel for programmatic inspection, structured GUI actions, static visual analysis, dynamic frame/timing analysis, network capture, multi-tab page groups, shared viewport control, a hybrid canvas, an element picker and client-side annotations. Other environments are planned and stay disabled in the runtime picker. **Install:** `dsh plugin --profile web add dsh-agent-team-ui-testing`. Capabilities, limits and verification are documented in [docs/capability-tiers.md](docs/capability-tiers.md) and [docs/verification.md](docs/verification.md).
|
|
23
|
+
|
|
24
|
+
## What is this?
|
|
25
|
+
|
|
26
|
+
**dsh-agent-team-ui-testing** is a UI testing infrastructure plugin for [DeepSeekHarness (DSH)](https://github.com/deepseek-ai/deepseek-harness). It lets an AI agent — or a coordinated Agent Team — drive a real application, inspect what the application exposes, verify expected behavior, collect reviewable evidence and report actionable failures.
|
|
27
|
+
|
|
28
|
+
The runtime is built around a shared Chromium instance with one isolated page per DSH workspace, a typed tool surface, and a human-facing debug panel. The same session can be inspected programmatically, operated through structured DOM/accessibility data, captured as screenshots, or analyzed visually.
|
|
29
|
+
|
|
30
|
+
The project grows out of the earlier `dsh-agent-team-browser` idea. The shared browser workspace remains the first adapter of a broader, capability-aware UI testing runtime.
|
|
31
|
+
|
|
32
|
+
## Why build it?
|
|
33
|
+
|
|
34
|
+
Coding agents can produce UI code without being able to answer: **“Does the finished application actually work and look right?”** A 200 response, a running process or a single screenshot is not proof of a working user journey.
|
|
35
|
+
|
|
36
|
+
This project focuses on:
|
|
37
|
+
|
|
38
|
+
- **Real UI feedback** — exercise user journeys on rendered interfaces, not only source code.
|
|
39
|
+
- **Structured-first automation** — prefer APIs, DOM and accessibility data; use vision when structure is insufficient.
|
|
40
|
+
- **Evidence-based results** — record what ran, what was observed, what passed, what failed and what remains unverified.
|
|
41
|
+
- **Human control** — authorized access, scoped sessions and a panel humans can watch or take over.
|
|
42
|
+
- **Low disruption** — prefer background browser operations over hijacking the desktop foreground.
|
|
43
|
+
|
|
44
|
+
## What works today
|
|
45
|
+
|
|
46
|
+
- **Shared browser runtime** — one browser per host and per runtime provider (the system Chrome/Chromium or Edge binary; the plugin does not bundle or install a browser), headless by default with an optional headed mode in the Web view (off-screen hidden window + persistent profile); each DSH workspace gets its own page, URL, viewport, history, network buffer and lease. Cookies and storage are shared by the profile of the active provider.
|
|
47
|
+
- **Runtime providers** — the web target environment defaults to `chrome` and also has a wired `edge` provider: its own executable candidates, its own `DSH_UI_TESTING_EDGE` override, its own profile directory and a post-connect product-identity check, reusing the same CDP stack. **A real Edge launch is not verified**: while Edge stays disabled its dependency axis is `not-probed` (disabled providers are never probed); once enabled on a machine without an Edge binary it reports `failed / executable-missing` on the Edge card, and enabling it opens no page. In the settings page the group header is the target-environment switch and each card is a runtime-provider switch; turning the total switch off greys the per-provider switches out while keeping their saved values.
|
|
48
|
+
- **37 agent tools** across programmatic, structured GUI, static vision, dynamic behavior, network debugging, per-workspace tab management and annotations.
|
|
49
|
+
- **Multi-tab page group (P0-E)** — page groups are keyed by (workspace, provider, team root): one team root shares a primary page plus up to three child tabs, while a different independent session or root gets its own group it can neither see nor write. Child tabs (max three) are counted per (workspace, provider) across roots; global live pages stay 8. Per-agent work/observation selections, long-lived ownership and Lead acquire/release/transfer control come on top of the short per-tab lease.
|
|
50
|
+
- **Dynamic behavior (T4)** — real CDP screencast plus a screenshot-loop path, a bounded frame store with integrity counters, seven deterministic motion analyses, WAAPI motion control with restore, region-only frame delivery, and six-direction frame↔network event correlation.
|
|
51
|
+
- **Debug panel** — live preview, responsive size controls, shared viewport state, a hybrid canvas, and a client-side annotation layer that agents can read back.
|
|
52
|
+
- **Element picker** — select an element in the panel preview to append its node description to the chat as an `@` reference chip; the model receives the full text block and the page is not modified.
|
|
53
|
+
- **Evidence and safety** — typed errors, structured action evidence, validated PNG capture, managed visual baselines, network evidence and optimistic concurrency for shared state.
|
|
54
|
+
|
|
55
|
+
### Agent tools
|
|
56
|
+
|
|
57
|
+
| Group | Tools | What it covers |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| **Programmatic** (10) | `browser_navigate` `browser_eval` `browser_screenshot` `browser_input` `browser_network` `browser_computed_style` `browser_http_request` `browser_viewport` `browser_state` `browser_capabilities` | Navigation, JavaScript, console/network inspection, independent HTTP requests, computed styles, screenshots, raw mouse/wheel/keyboard input, shared viewport state and capability reporting |
|
|
60
|
+
| **Annotations** (1) | `browser_annotation` | Read/draw/erase/clear the annotation document the human sees in the debug panel: six shape types with colour, stroke width and fill/stroke style, append-only draws, revision CAS and a hard foreground requirement |
|
|
61
|
+
| **Page group** (1) | `browser_tabs` | Primary + up to three child tabs per (workspace, provider, root), per-tab short leases, per-agent work/observation selection, ownership + Lead control (acquire/release/transfer) and tab lifecycle (list/current/select/open/close/wait/acquire/release/transfer) |
|
|
62
|
+
| **Structured GUI** (7) | `browser_snapshot` `browser_click` `browser_type` `browser_scroll` `browser_fill_form` `browser_node_state` `browser_wait_for` | Snapshot → ref targeting, trusted input, forms, node state and waits, with structured evidence and typed errors |
|
|
63
|
+
| **Static vision** (6) | `browser_vision_image` `browser_vision_find` `browser_vision_compare` `browser_vision_act` `browser_vision_baseline` `browser_vision_check` | Crop/zoom/preprocess/annotate PNGs, deterministic colour/component/edge/template finders, YIQ diff, coordinate input, managed baselines and visual assertions |
|
|
64
|
+
| **Dynamic** (5) | `browser_dynamic_session` `browser_motion_observe` `browser_motion_analyze` `browser_motion_control` `browser_dynamic_correlate` | Bounded frame capture with integrity counters, region-only frame delivery, seven motion/transition analyses, WAAPI pause/seek/rate/restore, and six-direction frame↔network correlation |
|
|
65
|
+
| **Network** (7) | `browser_network_session` `browser_network_events` `browser_network_detail` `browser_network_trace` `browser_network_control` `browser_network_evidence` `browser_network_subscribe` | Capture, timeline, analysis, business-step traces, interception/throttling/replay/mock, JSONL/HAR evidence and per-agent subscriptions |
|
|
66
|
+
|
|
67
|
+
### Debug panel
|
|
68
|
+
|
|
69
|
+
The panel is the human window into the same runtime the agent uses.
|
|
70
|
+
|
|
71
|
+
- **Live preview** of the workspace page, driven by a screencast with a polling fallback.
|
|
72
|
+
- **Size bar** — 宽屏 / 横屏 / 平板 / 手机 presets as a segmented control, X/Y canvas position, width × height, display scale, and a `拖拽 | 适应窗口 | 默认` mode selector. Preset clicks reset X/Y and keep the chosen display mode; the selected preset shows a green dot and is mutually exclusive with drag mode.
|
|
73
|
+
- **Hybrid canvas** — the viewport can be positioned like a canvas: a signed origin, negative coordinates and blank areas, a dark checkerboard in the panel (pure white in screenshots), drag-to-pan and screen-anchored wheel zoom.
|
|
74
|
+
- **Annotation mode** — six shapes (circle/ellipse, rectangle, line, arrow, brush and text), plus eraser, fill/outline, colour, width and clear-canvas controls. Drawings are anchored in canvas coordinates and the page receives no input while annotating. When a user refers to annotations, drawings, circles, boxes, arrows or handwriting, agents read `browser_state.annotations` and call `browser_screenshot {includeAnnotations:true}` to see the overlay. The screenshot renders the Host-accepted, submitted document with the same shape semantics and region/scale mapping as the panel; drafts, toolbars and selection controls are excluded. `includeAnnotations` is a boolean, default `false`; default screenshots and T3/T4 source images omit panel annotations. See [capture and annotation boundaries](docs/capture-p0.md).
|
|
75
|
+
- **Shared state** — agent and panel read the same viewport; updates use `expectedRevision`, and conflicts are reported instead of silently overwriting.
|
|
76
|
+
|
|
77
|
+
### Evidence and safety
|
|
78
|
+
|
|
79
|
+
- Every structured action can return evidence: target identity, before/after state, dispatch facts, network deltas and typed errors.
|
|
80
|
+
- Screenshots are validated PNGs with explicit scale and canvas-space regions; capture can be staged or persisted under a controlled root.
|
|
81
|
+
- Visual baselines are immutable revisions with compare-and-swap HEAD updates and tombstones.
|
|
82
|
+
- Network evidence supports JSONL (lossless) and HAR 1.2 export with default redaction and explicit truncation counters.
|
|
83
|
+
- Frame evidence keeps the original `sourceTimestamp`, separate encoded and RGBA hashes, and dropped/evicted/gap counters; motion analyses are deterministic and report budget exhaustion or timeout as `BLOCKED` instead of pretending to pass.
|
|
84
|
+
- Runtime access is scoped to a DSH workspace; mutating page work is serialized through a lease and a serial queue.
|
|
85
|
+
- Navigation is restricted to approved targets (loopback by default; private ranges blocked unless explicitly enabled), with DNS, redirect and popup checks.
|
|
86
|
+
|
|
87
|
+
## Architecture design philosophy
|
|
88
|
+
|
|
89
|
+
> **In one sentence:** the AI agent decides *what to test and how to judge it*; the plugin *connects, controls, observes, and preserves evidence*; and the target runtime *actually runs the application*. **Web / Chromium is the implemented target today.** The three adapter contracts (`TargetAdapter` / `CapabilityAdapter` / `P0Provider`), the `core/` + `targets/` split, host-authoritative config, per-step tool admission and environment-aware Skill discovery are implemented for Web; the `engines/` boundary and other platform adapters remain planned.
|
|
90
|
+
|
|
91
|
+
### Three perspectives on the same test
|
|
92
|
+
|
|
93
|
+
```mermaid
|
|
94
|
+
mindmap
|
|
95
|
+
root((UI automation testing))
|
|
96
|
+
Execution architecture
|
|
97
|
+
Five-node control chain
|
|
98
|
+
Commands and observations
|
|
99
|
+
Shared human debug view
|
|
100
|
+
Capability architecture
|
|
101
|
+
T1 Programmatic
|
|
102
|
+
T2 Structured GUI
|
|
103
|
+
T3 Static vision
|
|
104
|
+
T4 Dynamic vision
|
|
105
|
+
Infrastructure architecture
|
|
106
|
+
P0-A Image capture
|
|
107
|
+
P0-B Network evidence
|
|
108
|
+
P0-C Viewport control
|
|
109
|
+
P0-D Canvas and annotations
|
|
110
|
+
P0-E Page groups and targets
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Perspective | Question it answers | Implemented Web example |
|
|
114
|
+
| --- | --- | --- |
|
|
115
|
+
| **Execution architecture** | Who requests an action, who executes it, and how does the result return? | DSH Agent → plugin → CDP → Chromium → page, with results flowing back |
|
|
116
|
+
| **Capability architecture** | Which method provides sufficient evidence for the question? | T1 programmatic, T2 structured GUI, T3 single-frame vision, T4 temporal/frame vision |
|
|
117
|
+
| **Infrastructure architecture** | How are capture, network data, viewports, evidence, and shared state managed reliably? | P0-A–P0-E plus workspace sessions, leases, safety, and evidence mechanisms |
|
|
118
|
+
|
|
119
|
+
These are **three views of one system**, not three separate applications or sequential network layers. A single `browser_click` travels through the execution chain, exercises a T2 capability, and relies on shared infrastructure to retain reviewable information.
|
|
120
|
+
|
|
121
|
+
### The five-node debug chain: from agent to running application
|
|
122
|
+
|
|
123
|
+
```mermaid
|
|
124
|
+
flowchart TB
|
|
125
|
+
A["① AI Agent<br/>DeepSeek / Agent Team"]
|
|
126
|
+
C["② Debug Controller<br/>Unified plugin-side control"]
|
|
127
|
+
P["③ Communication Interface<br/>CDP / ADB / RPC / IPC"]
|
|
128
|
+
B["④ Debug Backend<br/>Built-in, third-party, or self-developed"]
|
|
129
|
+
R["⑤ Target Runtime<br/>Actual browser / application / device"]
|
|
130
|
+
A <-->|"Tasks, observations, verdicts"| C
|
|
131
|
+
C <-->|"Commands, events, evidence"| P
|
|
132
|
+
P <-->|"Protocol messages"| B
|
|
133
|
+
B <-->|"Operations and state"| R
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
1. **AI Agent** interprets the goal, selects T1–T4 methods, and evaluates whether evidence satisfies acceptance criteria. It may be DeepSeek in DSH or a coordinated Agent Team.
|
|
137
|
+
2. **Debug Controller** is the plugin's unified entry point for tools, authorization, workspace and target selection, sessions, concurrency, state, and evidence.
|
|
138
|
+
3. **Communication Interface** transports commands and events using CDP, ADB, RPC, IPC, or other platform-specific mechanisms. **The upper-level capability contract is standardized; the wire protocol need not be.**
|
|
139
|
+
4. **Debug Backend** executes commands and observes the runtime. It may be Chromium's built-in DevTools backend, an existing OS automation facility, or a future self-developed companion program.
|
|
140
|
+
5. **Target Runtime** actually hosts the application under test: Chromium, Android, desktop OS, game runtime, etc. It normally exists outside the plugin.
|
|
141
|
+
|
|
142
|
+
These are **logical responsibilities, not five mandatory processes**. Commands flow down; observations, frames, logs, and errors flow up. The human **debug panel is a side-channel view and control surface** for the same managed session, rather than a second independent copy of the tested page.
|
|
143
|
+
|
|
144
|
+
### Cross-environment reuse: `core`, `targets`, and `engines`
|
|
145
|
+
|
|
146
|
+
The five-node chain describes runtime responsibilities. These three module boundaries describe code ownership and reuse; they do **not** correspond one-to-one with the five nodes.
|
|
147
|
+
|
|
148
|
+
```mermaid
|
|
149
|
+
flowchart TB
|
|
150
|
+
AI["DSH Agent / Agent Team"] --> CORE["core · Unified controller<br/>Sessions, tools, permissions, evidence"]
|
|
151
|
+
CORE --> CONTRACT["Target Capability Contract<br/>Requests / results / errors / discovery"]
|
|
152
|
+
CONTRACT --> WEB["targets/web · Web Adapter"]
|
|
153
|
+
CONTRACT --> AND["targets/android · Android Adapter (planned)"]
|
|
154
|
+
CONTRACT --> MINI["targets/mini-program · Mini Program Adapter (planned)"]
|
|
155
|
+
WEB --> CDP["CDP"] --> CHROME["Chromium built-in Debug Backend"] --> PAGE["Web Runtime"]
|
|
156
|
+
AND --> ADB["ADB / RPC"] --> AUTOMATE["UI Automator / optional custom APK"] --> PHONE["Android Runtime"]
|
|
157
|
+
MINI --> API["Platform automation API"] --> MP["Platform debug backend"] --> MINIAPP["Mini Program Runtime"]
|
|
158
|
+
ENGINES["engines · Self-developed executors, if needed"] -. "Builds / supplies optional APK" .-> AUTOMATE
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Proposed module boundary | Responsibility | Relationship to the five nodes |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| **`core/`** | Unified tools, session/lease control, capability selection, shared P0 processing, evidence, errors, permissions, debug-view state | Primarily node ② |
|
|
164
|
+
| **`targets/`** | Environment adapters translate common capability requests into CDP/ADB/etc., normalize results, and honestly report supported/unsupported operations | Bridges node ② to nodes ③–⑤ |
|
|
165
|
+
| **`engines/`** | **Self-developed** executors that need separate builds or deployment, such as a possible Android accessibility Companion APK | Optional implementation of node ④ |
|
|
166
|
+
|
|
167
|
+
`targets/web` does not mean vendoring Chrome or Playwright. Nor does `engines/android` imply an APK is required: ADB / UI Automator may be sufficient for initial Android automation. **`core/` and `targets/` are now real directories**: `core/` owns the contracts, config, identity/geometry/clock, evidence and six-axis readiness; `targets/web` is the real Web adapter and `targets/fake` is a test-only contract fixture. `engines/` remains the reserved boundary for self-developed executors. The CDP integration and the 37 tool implementations still live in `index.js` (composition root / Web implementation), but admission, config and execution all go through the adapter boundary.
|
|
168
|
+
|
|
169
|
+
### Capability architecture: choose T1 / T2 / T3 / T4 as needed
|
|
170
|
+
|
|
171
|
+
Tiers classify **testing methods and the evidence they can supply**. They are **selection and fallback levels**, not a mandatory T1→T2→T3→T4 pipeline. Prefer the least expensive reliable method; escalate or combine methods only when the evidence is insufficient.
|
|
172
|
+
|
|
173
|
+
| Tier | Question | Implemented Web example | Representative agent tools |
|
|
174
|
+
| --- | --- | --- | --- |
|
|
175
|
+
| **T1 · Programmatic** | Is the API, program state, or runtime behavior correct? | CDP/HTTP/JavaScript, console, computed styles, page state | `browser_eval`, `browser_http_request`, `browser_network` |
|
|
176
|
+
| **T2 · Structured GUI** | Which element is present, and can it be operated correctly? | DOM/accessibility snapshots, `ref` targeting, forms, trusted input | `browser_snapshot`, `browser_click`, `browser_fill_form` |
|
|
177
|
+
| **T3 · Static vision** | Does one frame show a layout, color, or pixel-level defect? | PNG preprocessing, color/template matching, managed baselines and diffs | `browser_vision_find`, `browser_vision_compare`, `browser_vision_check` |
|
|
178
|
+
| **T4 · Dynamic vision** | Are transitions, animations, drags, and time-dependent behavior correct? | CDP screencast / screenshot loop, frame timing, deterministic motion analysis, frame↔network correlation | `browser_dynamic_session`, `browser_motion_analyze`, `browser_dynamic_correlate` |
|
|
179
|
+
|
|
180
|
+
**A successful T1 call is not a UI pass; a dispatched click is not proof of a successful login.** Select the observations relevant to the acceptance criteria. Current T3/T4 algorithms are deterministic and do not embed VLM/OCR; the AI agent can reason over the returned evidence. Adapters must report what their runtimes actually support, not invent UI trees or network telemetry to fill all four tiers.
|
|
181
|
+
|
|
182
|
+
### Infrastructure architecture: P0 is the shared foundation
|
|
183
|
+
|
|
184
|
+
P0 supports multiple tiers. T3 and T4 both depend on image capture; T1 and T4 can consume network events. **P0-A–P0-E are the names of today's Web facilities; cross-platform reuse requires separating portable data models from browser-specific semantics.**
|
|
185
|
+
|
|
186
|
+
| Infrastructure | Implemented Web form | Portable boundary / important caveat |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| **P0-A · Image capture** | CDP screenshots, validated PNGs, canvas-space regions, dimensions, evidence storage | Common capture/Frame model and coordinate mapping; acquisition remains adapter-specific |
|
|
189
|
+
| **P0-B · Network evidence** | CDP events, timelines/traces, JSONL/HAR, throttling and mocks | Common event/evidence model; other devices/processes may expose less traffic |
|
|
190
|
+
| **P0-C · Viewport control** | Shared viewport dimensions and display scale, revisions/conflicts, input-coordinate constraints | Common display-space/coordinate mapping; physical screens cannot always be freely resized |
|
|
191
|
+
| **P0-D · Hybrid canvas and annotations** | Preview canvas, pan/zoom, anchored annotations readable by agents | Shared human/agent observations; capture-to-input coordinate mapping must remain accurate |
|
|
192
|
+
| **P0-E · Page group management** | Workspace primary + up to three child tabs, leases, `selectedTab` | Generalize target/window/session selection; other platforms may have no browser tabs |
|
|
193
|
+
|
|
194
|
+
Workspace authorization, serialized mutations, evidence validation, typed errors, state revisions, and human reviewability are further cross-cutting concerns shared by the execution and capability layers.
|
|
195
|
+
|
|
196
|
+
### Walk through an implemented Web testing path
|
|
197
|
+
|
|
198
|
+
Example request: “Check that the login form can be operated, observe feedback after submission, and retain evidence.” This is an **illustrative call path**, not a claim that a real login test has passed.
|
|
199
|
+
|
|
200
|
+
```mermaid
|
|
201
|
+
sequenceDiagram
|
|
202
|
+
actor Human as Human
|
|
203
|
+
participant AI as DSH / DeepSeek
|
|
204
|
+
participant Core as Plugin tools and controller
|
|
205
|
+
participant CDP as CDP / Chromium Backend
|
|
206
|
+
participant Web as Web page
|
|
207
|
+
participant Panel as Debug panel
|
|
208
|
+
Human->>AI: Test login UI
|
|
209
|
+
AI->>Core: browser_navigate
|
|
210
|
+
Core->>CDP: Navigate
|
|
211
|
+
CDP->>Web: Load page
|
|
212
|
+
AI->>Core: browser_snapshot (T2)
|
|
213
|
+
Core->>CDP: Inspect DOM / accessibility
|
|
214
|
+
CDP-->>Core: Snapshot and element refs
|
|
215
|
+
Core-->>AI: Targetable elements
|
|
216
|
+
AI->>Core: browser_click / browser_fill_form (T2)
|
|
217
|
+
Core->>CDP: Dispatch input
|
|
218
|
+
CDP->>Web: Trigger interaction
|
|
219
|
+
Web-->>CDP: State, network, frame events
|
|
220
|
+
CDP-->>Core: Observations and capture
|
|
221
|
+
Core-->>AI: Structured action evidence
|
|
222
|
+
AI->>Core: browser_vision_check (T3, if needed)
|
|
223
|
+
Core-->>AI: Visual verdict and evidence
|
|
224
|
+
Core-->>Panel: Same-session frames and state
|
|
225
|
+
AI-->>Human: Findings, evidence, unknowns
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Mapped to the three perspectives: **execution** carries `browser_*` calls to Chromium and observations back; **capabilities** select T2 here and optionally T1 network checks, T3 single-frame vision, or T4 temporal analysis; **infrastructure** preserves captures, network evidence, and shared state so the human can inspect the same session. In the real implementation, `browser_http_request` uses an independent HTTP path—not every T1 operation goes through CDP. Panel preview is delivered via screencast and WebSocket, with HTTP polling as a fallback.
|
|
229
|
+
|
|
230
|
+
### What stays invariant for the next target?
|
|
231
|
+
|
|
232
|
+
- **Stable upper-level semantics:** agents request operations, observations, captures, events, and evidence through a common vocabulary; Web-only features remain target-specific extensions.
|
|
233
|
+
- **Adapters translate, never pretend:** Android may use ADB / UI Automator or an optional companion APK; Mini Program may use a platform's developer tools and automation interfaces. Unsupported capabilities must be reported explicitly.
|
|
234
|
+
- **Reuse analysis, vary acquisition:** T3 pixel comparison, T4 frame analysis, and P0 evidence models are candidates for reuse; CDP capture and Android screen capture use different backends.
|
|
235
|
+
- **Distinguish code ownership from deployment:** `targets/` lives on the controller side, `engines/` holds optional self-developed executors, and real Chrome / Android / Mini Program runtimes live outside the repository.
|
|
236
|
+
- **Load targets on demand:** future target selection should avoid needlessly injecting disabled platforms' tool schemas, skill content, or runtime dependencies into the AI agent's context.
|
|
237
|
+
|
|
238
|
+
**Implementation boundary:** Web / Chromium currently provides 37 tools and T1–T4/P0-related features, subject to the coverage and limitations in [capability tiers](docs/capability-tiers.md), [architecture](docs/architecture.md), and [verification](docs/verification.md). T4 acceptance is still partial. The cross-environment contracts, host-authoritative config, config-driven tool/Skill isolation and six-axis readiness are implemented and tested for Web plus a test-only fake adapter; real desktop, Android, Mini Program and other platform adapters remain proposed work.
|
|
239
|
+
|
|
240
|
+
## Getting started
|
|
241
|
+
|
|
242
|
+
**Requirements:** a DSH installation and a local Chrome/Chromium binary for the default `chrome` runtime provider. Edge is supported as a second runtime provider with its own executable candidates and its own `DSH_UI_TESTING_EDGE` override; its driver code is wired to the same CDP stack, but a real Edge launch has not been verified on this machine — enabling Edge without an Edge binary makes its dependency axis report `failed / executable-missing` (a disabled provider stays `not-probed`) and opens no page. The plugin does not bundle or install a browser; it launches the system binary it resolves (see [docs/getting-started.md](docs/getting-started.md)). A headed Web view additionally needs `DISPLAY` or `WAYLAND_DISPLAY` on POSIX hosts; Windows hosts always provide a window system, so headed mode needs no such variable there. The plugin requires Node.js 22+ (native `WebSocket`); the current DSH release itself requires Node.js 24.9+, so a real DSH host follows the stricter version.
|
|
243
|
+
|
|
244
|
+
The plugin ships as a DSH plugin bundle and is published on npm as `dsh-agent-team-ui-testing`. There is no compatibility matrix beyond the Node.js and DSH requirements above.
|
|
245
|
+
|
|
246
|
+
```sh
|
|
247
|
+
# npm form (recommended): follows semver, so dsh-market can prompt for updates
|
|
248
|
+
dsh plugin --profile web add dsh-agent-team-ui-testing
|
|
249
|
+
|
|
250
|
+
# floating GitHub form: also receives updates, but only when package.json version is bumped
|
|
251
|
+
dsh plugin --profile web add github:bloodarea/dsh-agent-team-ui-testing
|
|
252
|
+
|
|
253
|
+
# pinned tag: reproduces exactly one release and never receives update prompts
|
|
254
|
+
dsh plugin --profile web add github:bloodarea/dsh-agent-team-ui-testing#vX.Y.Z
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
1. Install the package into the DSH profile being used.
|
|
258
|
+
2. Restart DSH after the first install so the plugin bundle is registered.
|
|
259
|
+
3. Open the debug view from **更多 → 调试视图**, or from the plugin card in the right sidebar.
|
|
260
|
+
4. Changes to `client.js` only need a panel refresh; changes to `index.js`, the tool surface or bundled skills need a DSH restart.
|
|
261
|
+
|
|
262
|
+
For plugin development, link or copy this repository into the profile instead of installing the npm package.
|
|
263
|
+
|
|
264
|
+
Requirements, install steps and panel usage are in [docs/getting-started.md](docs/getting-started.md).
|
|
265
|
+
|
|
266
|
+
A typical agent flow is: navigate to the target, inspect state with `browser_state`/`browser_eval`, perform structured actions with the T2 tools, capture screenshots or run T3 checks, inspect network traffic with the network tools, escalate to the dynamic tools (`browser_dynamic_session` → `browser_motion_observe` → `browser_motion_analyze`/`browser_dynamic_correlate`) when the question is about motion, timing or a frame sequence, and use the shared viewport/canvas/annotation state when the task involves layout, framing or visual feedback.
|
|
267
|
+
|
|
268
|
+
## Current limits
|
|
269
|
+
|
|
270
|
+
- **Web target only.** Web/Chromium is the only implemented target environment and runs on Linux, macOS and Windows hosts. Desktop applications, Android, Mini Program, TUI, HarmonyOS, games and 3D are planned targets and stay disabled in the runtime picker.
|
|
271
|
+
- **Vision is deterministic, not semantic.** T3 judges single PNGs and T4 judges frame sequences with deterministic algorithms: no VLM/OCR, no semantic naming, so "what does this text mean" and "looks right to a human" stay out of scope.
|
|
272
|
+
- **T4 verification is partial.** Of the 44 dynamic-behavior criteria, 12 pass, 20 are partial, 0 fail and 12 were not run — the suite exits non-zero only because required checks were not run, not because they failed. Close/dispose restore, WebGPU rendering, media seeking/stalling, header-verified identity, 16 ms flicker coverage and long-lived connections remain unverified.
|
|
273
|
+
- **Shared browser profile.** Cookies and storage are shared by the Chromium profile; only page, URL, viewport, history, network buffer and leases are isolated per workspace.
|
|
274
|
+
- **Screenshots are not redacted.** Review their content before sharing.
|
|
275
|
+
- **Attachments are not provider visibility.** A returned image attachment does not prove the model received it at full resolution.
|
|
276
|
+
- **Network capture is partial at the edges.** Same-page iframe and dedicated workers are covered; OOPIF is partial; shared and service workers are not collected; HAR is a 1.2 subset; body/header redaction is not a general secret detector.
|
|
277
|
+
- **Viewport display is a 1× screencast.** A display scale above 100% magnifies the bitmap rather than adding pixel density; request an explicit screenshot scale when resolution matters. Resize input barriers are best-effort, while canvas offsets use a fail-closed barrier.
|
|
278
|
+
- **Shared state is optimistic.** `browser_viewport get` is a cache diagnostic; `stale` means “not recently observed”, and a lost `expectedRevision` race returns `VIEWPORT_CONFLICT` instead of replaying the patch.
|
|
279
|
+
|
|
280
|
+
## Roadmap
|
|
281
|
+
|
|
282
|
+
- Harden the Web channel and close the remaining dynamic-behavior criteria (12 not run, 20 partial).
|
|
283
|
+
- Gradually extract a common capability contract and `core/targets/engines` module boundaries while preserving existing Web tools; build the cross-environment test core (typed sessions, observations, assertions, reports).
|
|
284
|
+
- Validate desktop (Windows/Linux/macOS), Android, Mini Program, TUI, HarmonyOS, game and 3D adapters by demand and platform feasibility.
|
|
285
|
+
- Add multi-agent scheduling, human takeover and release hardening.
|
|
286
|
+
|
|
287
|
+
## Documentation
|
|
288
|
+
|
|
289
|
+
| File | Contents |
|
|
290
|
+
| --- | --- |
|
|
291
|
+
| [docs/index.md](docs/index.md) | Documentation index |
|
|
292
|
+
| [docs/getting-started.md](docs/getting-started.md) | Requirements, install, debug panel and first calls |
|
|
293
|
+
| [docs/tools.md](docs/tools.md) | All 37 tools, parameters and error classes |
|
|
294
|
+
| [docs/capability-tiers.md](docs/capability-tiers.md) | T1–T4 selection model, P0 infrastructure and known limits |
|
|
295
|
+
| [docs/viewport-control.md](docs/viewport-control.md) | Shared viewport, hybrid canvas and annotations |
|
|
296
|
+
| [docs/capture-p0.md](docs/capture-p0.md) | Screenshots, image delivery and file lifecycle |
|
|
297
|
+
| [docs/multi-tab.md](docs/multi-tab.md) | Per-workspace tab group, per-tab leases and agent tab selection |
|
|
298
|
+
| [docs/element-picker.md](docs/element-picker.md) | Panel element picking and `@` element reference chips |
|
|
299
|
+
| [docs/network-p0.md](docs/network-p0.md) | Network capture, tracing, control and evidence |
|
|
300
|
+
| [docs/t2-structured-gui.md](docs/t2-structured-gui.md) | Snapshot/ref, trusted input and form filling |
|
|
301
|
+
| [docs/t3-vision.md](docs/t3-vision.md) | Static vision algorithms, baselines and verdicts |
|
|
302
|
+
| [docs/t4-dynamic-behavior.md](docs/t4-dynamic-behavior.md) | Frame capture, motion analysis, control and correlation |
|
|
303
|
+
| [docs/architecture.md](docs/architecture.md) | Runtime, module responsibilities and extension points |
|
|
304
|
+
| [docs/verification.md](docs/verification.md) | Reproducible tests, result interpretation and contributing |
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
## Relationship to other projects
|
|
308
|
+
|
|
309
|
+
| Project | Role |
|
|
310
|
+
| --- | --- |
|
|
311
|
+
| [`dsh-agent-team-presets`](https://github.com/bloodarea/dsh-agent-team-presets) | Reusable team and role configurations, model routes and tool policies |
|
|
312
|
+
| **`dsh-agent-team-ui-testing`** | UI testing targets, sessions, automation, evidence and governed human/agent control |
|
|
313
|
+
|
|
314
|
+
They are complementary but do not require each other; the runtime supports a single DSH agent without the presets plugin.
|
|
315
|
+
|
|
316
|
+
## Contributing
|
|
317
|
+
|
|
318
|
+
Reproducible DSH integration findings, platform feasibility tests, accessibility/DOM fallback cases, security threat models and concrete UI acceptance scenarios are the most useful contributions.
|
|
319
|
+
|
|
320
|
+
When filing an issue, include the DSH version/commit, platform and runtime versions, reproduction steps, expected and observed results, and sanitized evidence. Never upload credentials, personal device data or unredacted authenticated traffic.
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
Released under the [MIT License](LICENSE). Copyright (c) 2026 bloodarea. Third-party code incorporated later must retain its applicable notices.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
**Repository:** [bloodarea/dsh-agent-team-ui-testing](https://github.com/bloodarea/dsh-agent-team-ui-testing) · **Maintainer:** [bloodarea](https://github.com/bloodarea) · **Status:** pre-release
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rasterize the panel's accepted annotation document in a CDP isolated world.
|
|
3
|
+
* This function is serialized into Chromium: it must close over no Host values. Its detached
|
|
4
|
+
* OffscreenCanvas never changes the target DOM, styles, focus, viewport or preview, and needs no
|
|
5
|
+
* image/network loads (including on pages with img-src 'none'). Geometry and styles mirror
|
|
6
|
+
* client.js renderAnnotShape/annotArrowGeometry; the input is Host-normalized shape data only.
|
|
7
|
+
*/
|
|
8
|
+
export async function renderAnnotationOverlay({ shapes, region, width, height }) {
|
|
9
|
+
const canvas = new OffscreenCanvas(width, height);
|
|
10
|
+
const ctx = canvas.getContext('2d');
|
|
11
|
+
if (!ctx) throw new Error('annotation 2d context unavailable');
|
|
12
|
+
ctx.setTransform(width / region.width, 0, 0, height / region.height,
|
|
13
|
+
-region.x * width / region.width, -region.y * height / region.height);
|
|
14
|
+
const rounded = value => Math.round(value * 100) / 100;
|
|
15
|
+
for (const shape of shapes) {
|
|
16
|
+
ctx.fillStyle = shape.color;
|
|
17
|
+
ctx.strokeStyle = shape.color;
|
|
18
|
+
ctx.lineWidth = shape.strokeWidth;
|
|
19
|
+
ctx.lineCap = 'butt';
|
|
20
|
+
ctx.lineJoin = 'miter';
|
|
21
|
+
ctx.beginPath();
|
|
22
|
+
if (shape.type === 'rect' || shape.type === 'circle') {
|
|
23
|
+
if (shape.type === 'rect') ctx.rect(shape.x, shape.y, shape.width, shape.height);
|
|
24
|
+
else ctx.ellipse(shape.cx, shape.cy, shape.rx, shape.ry, 0, 0, Math.PI * 2);
|
|
25
|
+
if (shape.fill) ctx.fill();
|
|
26
|
+
if (shape.stroke) ctx.stroke();
|
|
27
|
+
} else if (shape.type === 'line') {
|
|
28
|
+
ctx.lineCap = 'round';
|
|
29
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
30
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
31
|
+
ctx.stroke();
|
|
32
|
+
} else if (shape.type === 'arrow') {
|
|
33
|
+
const dx = shape.x2 - shape.x1, dy = shape.y2 - shape.y1;
|
|
34
|
+
const length = Math.hypot(dx, dy);
|
|
35
|
+
const headLength = Math.min(3 * shape.strokeWidth, length);
|
|
36
|
+
const headWidth = Math.min(2 * shape.strokeWidth, length);
|
|
37
|
+
const ux = length ? dx / length : 0, uy = length ? dy / length : 0;
|
|
38
|
+
const bx = shape.x2 - ux * headLength, by = shape.y2 - uy * headLength;
|
|
39
|
+
ctx.lineCap = 'round';
|
|
40
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
41
|
+
ctx.lineTo(bx, by);
|
|
42
|
+
ctx.stroke();
|
|
43
|
+
if (length) {
|
|
44
|
+
// The panel rounds polygon/polyline point strings to two decimal places.
|
|
45
|
+
ctx.beginPath();
|
|
46
|
+
ctx.moveTo(rounded(shape.x2), rounded(shape.y2));
|
|
47
|
+
ctx.lineTo(rounded(bx - uy * headWidth / 2), rounded(by + ux * headWidth / 2));
|
|
48
|
+
ctx.lineTo(rounded(bx + uy * headWidth / 2), rounded(by - ux * headWidth / 2));
|
|
49
|
+
ctx.closePath();
|
|
50
|
+
ctx.fill();
|
|
51
|
+
}
|
|
52
|
+
} else if (shape.type === 'brush') {
|
|
53
|
+
ctx.lineCap = 'round';
|
|
54
|
+
ctx.lineJoin = 'round';
|
|
55
|
+
shape.points.forEach((point, index) => {
|
|
56
|
+
// Host wire data stores a point as [x,y]; the panel converts it to an object only
|
|
57
|
+
// when importing into its local editor. Render the accepted wire document directly.
|
|
58
|
+
if (index) ctx.lineTo(rounded(point[0]), rounded(point[1]));
|
|
59
|
+
else ctx.moveTo(rounded(point[0]), rounded(point[1]));
|
|
60
|
+
});
|
|
61
|
+
ctx.stroke();
|
|
62
|
+
} else if (shape.type === 'text') {
|
|
63
|
+
ctx.font = '400 20px system-ui, -apple-system, "Segoe UI", sans-serif';
|
|
64
|
+
ctx.textBaseline = 'alphabetic';
|
|
65
|
+
// SVG text-before-edge aligns the font's ascent box, whereas Canvas 'top' aligns its em
|
|
66
|
+
// square. Use font metrics so CJK/fallback fonts retain the panel's baseline.
|
|
67
|
+
// SVG's default white-space processing collapses interior spaces and trims the edges.
|
|
68
|
+
const text = shape.text.replace(/[\t\r\n]/g, ' ').replace(/ +/g, ' ').trim();
|
|
69
|
+
const ascent = ctx.measureText(text).fontBoundingBoxAscent;
|
|
70
|
+
ctx.fillText(text, shape.x, shape.y + ascent);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const blob = await canvas.convertToBlob({ type: 'image/png' });
|
|
74
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
75
|
+
let binary = '';
|
|
76
|
+
for (let offset = 0; offset < bytes.length; offset += 32768) {
|
|
77
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
78
|
+
}
|
|
79
|
+
return { base64: btoa(binary), width, height };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Source-over a transparent annotation raster onto the already-captured browser pixels. */
|
|
83
|
+
export function compositeAnnotationPixels(page, overlay) {
|
|
84
|
+
if (page.width !== overlay.width || page.height !== overlay.height) {
|
|
85
|
+
throw new Error('annotation raster dimensions differ from page capture');
|
|
86
|
+
}
|
|
87
|
+
// Chromium emits RGBA for the transparent overlay; refusing another model avoids interpreting
|
|
88
|
+
// a missing alpha channel as opaque. Page PNGs may be RGB, RGBA or grayscale.
|
|
89
|
+
if (overlay.channels !== 4) throw new Error('annotation raster must contain RGBA pixels');
|
|
90
|
+
const rgba = new Uint8Array(page.width * page.height * 4);
|
|
91
|
+
if (page.channels === 4) rgba.set(page.data);
|
|
92
|
+
else for (let pixel = 0; pixel < page.width * page.height; pixel++) {
|
|
93
|
+
const source = pixel * page.channels, target = pixel * 4;
|
|
94
|
+
rgba[target] = page.data[source];
|
|
95
|
+
rgba[target + 1] = page.channels === 3 ? page.data[source + 1] : page.data[source];
|
|
96
|
+
rgba[target + 2] = page.channels === 3 ? page.data[source + 2] : page.data[source];
|
|
97
|
+
rgba[target + 3] = page.channels === 2 ? page.data[source + 1] : 255;
|
|
98
|
+
}
|
|
99
|
+
for (let offset = 0; offset < rgba.length; offset += 4) {
|
|
100
|
+
const alpha = overlay.data[offset + 3];
|
|
101
|
+
if (!alpha) continue;
|
|
102
|
+
const a = alpha / 255, b = rgba[offset + 3] / 255;
|
|
103
|
+
const outAlpha = a + b * (1 - a);
|
|
104
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
105
|
+
rgba[offset + channel] = Math.round((overlay.data[offset + channel] * a
|
|
106
|
+
+ rgba[offset + channel] * b * (1 - a)) / outAlpha);
|
|
107
|
+
}
|
|
108
|
+
rgba[offset + 3] = Math.round(outAlpha * 255);
|
|
109
|
+
}
|
|
110
|
+
return { width: page.width, height: page.height, rgba };
|
|
111
|
+
}
|
package/banner.png
ADDED
|
Binary file
|
package/banner_zh.png
ADDED
|
Binary file
|