@a11y-oracle/visual-engine

中文文档
1.3.2发布于 2026/03/12MITTypeScriptES Module近 30 天下载 3101

Visual pixel analysis engine for color contrast resolution using CDP screenshot capture and luminance analysis

原始使用文档
文档目录12 节
  1. Installation
  2. Usage
  3. VisualContrastAnalyzer (Recommended)
  4. Individual Pipeline Steps
  5. Analysis Pipeline
  6. API Reference
  7. VisualContrastAnalyzer
  8. Halo Detection
  9. Pixel Analysis
  10. Screenshot Capture
  11. Types
  12. Dependencies

@a11y-oracle/visual-engine

Visual pixel analysis engine for resolving incomplete color contrast warnings from axe-core. Provides CSS halo heuristic detection, CDP-based screenshot capture, and pixel-level luminance analysis using the WCAG Safe Assessment Matrix.

Installation

npm install @a11y-oracle/visual-engine

Note: Most users should use @a11y-oracle/axe-bridge instead, which wraps this engine and integrates directly with axe-core results. Install the visual-engine directly only if you need fine-grained control over individual analysis steps or are building a custom integration.

Usage

The coordinator class runs the full pipeline for a single element:

import { VisualContrastAnalyzer } from '@a11y-oracle/visual-engine';
import type { CDPSessionLike } from '@a11y-oracle/cdp-types';

const analyzer = new VisualContrastAnalyzer(cdpSession);

const result = await analyzer.analyzeElement('#hero-text', 4.5);

switch (result.category) {
  case 'pass':       // Worst-case contrast passes threshold
  case 'violation':  // Best-case contrast fails threshold
  case 'incomplete': // Split decision, dynamic content, or unresolvable
}

Individual Pipeline Steps

Each stage of the pipeline is also exported for advanced use:

import {
  getElementStyles,
  captureElementBackground,
  analyzeHalo,
  extractPixelLuminance,
} from '@a11y-oracle/visual-engine';

// 1. Get computed styles via CDP
const styles = await getElementStyles(cdp, '#my-element');

// 2. CSS halo fast path (no screenshot needed)
const halo = analyzeHalo(styles, 4.5);
if (halo.hasValidHalo) {
  // Element has a valid text stroke or shadow halo
}

// 3. Capture background with text hidden
const capture = await captureElementBackground(cdp, '#my-element');

// 4. Pixel-level luminance analysis
const pixels = extractPixelLuminance(capture.pngBuffer, capture.textColor);

Analysis Pipeline

The VisualContrastAnalyzer.analyzeElement() method runs this pipeline:

  1. Get Computed Styles — Fetches color, backgroundColor, textStrokeWidth, textStrokeColor, textShadow, and backgroundImage via CDP Runtime.evaluate.

  2. Dynamic Content Check — Detects video/canvas ancestors, sub-1 opacity, and CSS blend modes. Dynamic content is left as incomplete.

  3. CSS Halo Heuristic (fast path) — Checks for:

    • -webkit-text-stroke >= 1px with sufficient contrast against the background
    • text-shadow with 4+ zero-blur directional shadows covering all quadrants

    If a valid halo is found and its color passes the threshold against the background, the element passes without a screenshot.

  4. Screenshot Capture — Scrolls the element into the viewport (ensuring off-screen elements produce valid screenshots), hides the element's text (sets color: transparent), captures a clipped screenshot via CDP Page.captureScreenshot, then restores the text.

  5. Pixel Analysis — Decodes the PNG, scans all opaque pixels for luminance extremes (lightest and darkest), and computes contrast ratios against the text color.

  6. Safe Assessment Matrix:

    • Pass: Text contrast against the lightest AND darkest background pixels both meet the threshold (worst-case passes)
    • Violation: Text contrast against the lightest AND darkest background pixels both fail the threshold (best-case fails)
    • Incomplete: One passes and one fails (split decision) — cannot safely categorize

API Reference

VisualContrastAnalyzer

constructor(cdp: CDPSessionLike)

Create an analyzer bound to a CDP session.

analyzeElement(selector, threshold?): Promise<ContrastAnalysisResult>

Run the full pipeline on an element.

  • selector — CSS selector targeting the element
  • threshold — Minimum contrast ratio (default: 4.5)
  • Returns — ContrastAnalysisResult with category, textColor, halo, pixels, and reason

Halo Detection

analyzeHalo(styles, threshold?): HaloResult

Check if computed styles contain a valid CSS halo.

  • styles — ElementComputedStyles from getElementStyles()
  • threshold — Minimum contrast ratio (default: 4.5)
  • Returns — HaloResult with hasValidHalo, haloContrast, method, and skipReason

parseTextShadow(css): TextShadowPart[]

Parse a CSS text-shadow value into structured parts.

Pixel Analysis

extractPixelLuminance(pngBuffer, textColor): PixelAnalysisResult | null

Decode a PNG and compute contrast ratios against a text color.

  • pngBuffer — Raw PNG buffer from captureElementBackground()
  • textColor — RGBColor of the foreground text
  • Returns — Luminance extremes and contrast ratios, or null if no opaque pixels

decodePng(buffer): { width, height, data: Uint8Array }

Decode a PNG buffer into raw RGBA pixel data.

Screenshot Capture

getElementStyles(cdp, selector): Promise<ElementComputedStyles | null>

Fetch computed styles for an element via CDP.

captureElementBackground(cdp, selector): Promise<{ pngBuffer: Buffer; textColor: RGBColor | null } | null>

Capture a clipped screenshot of an element with its text hidden. Automatically scrolls the element into the viewport before capture, ensuring elements below the fold produce valid screenshots instead of blank images.

Types

import type {
  ContrastAnalysisResult,  // Full analysis result
  ContrastCategory,        // 'pass' | 'violation' | 'incomplete'
  HaloResult,              // CSS halo analysis result
  PixelAnalysisResult,     // Luminance extremes + contrast ratios
  TextShadowPart,          // Parsed text-shadow entry
  ElementComputedStyles,   // Computed CSS properties for contrast analysis
} from '@a11y-oracle/visual-engine';

Dependencies

  • @a11y-oracle/focus-analyzer — Reuses relativeLuminance(), contrastRatio(), and parseColor() for WCAG-compliant color math
  • @a11y-oracle/cdp-types — CDPSessionLike interface for framework-agnostic CDP access
  • fast-png — Pure TypeScript PNG decoder/encoder (browser + Node.js compatible, no native dependencies)

版本与发布记录

@a11y-oracle/visual-engine 共发布 10 个版本,首次发布于 2026/03/05;过去 12 个月发布了 10 个版本。

版本发布日期距今
1.3.2latest2026/03/127 个月前
1.3.12026/03/117 个月前
1.3.02026/03/068 个月前
1.2.02026/03/068 个月前
1.1.42026/03/068 个月前
1.1.32026/03/068 个月前

关于 @a11y-oracle/visual-engine 的常见问题

@a11y-oracle/visual-engine 是什么?

Visual pixel analysis engine for color contrast resolution using CDP screenshot capture and luminance analysis

如何安装 @a11y-oracle/visual-engine?

在项目目录运行 npm install @a11y-oracle/visual-engine,或使用 pnpm add / yarn add / bun add。

@a11y-oracle/visual-engine 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@a11y-oracle/visual-engine 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@a11y-oracle/visual-engine 可以商用吗?

@a11y-oracle/visual-engine 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@a11y-oracle/visual-engine 的下载量有多少?

根据 npm 官方下载统计,@a11y-oracle/visual-engine 在 2026/10/05 – 2026/11/03 这 30 天内被下载 3,101 次,日均约 103 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@a11y-oracle/visual-engine 还在维护吗?

最新版本 1.3.2 发布于 2026/03/12(7 个月前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/03/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。