visual-overlay

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Visual Overlay for AgentPulse

AgentPulse视觉覆盖层

Add animated cursor, typing, and click effects to show users what the AI agent is doing.
为用户添加动画光标、打字和点击效果,展示AI Agent的操作过程。

Quick Start

快速开始

Add
VisualOverlay
inside your
AgentPulseProvider
:
tsx
import { AgentPulseProvider, VisualOverlay } from 'agentpulse';

function App() {
  return (
    <AgentPulseProvider endpoint="ws://localhost:3100/ws">
      <VisualOverlay />
      <MyApp />
    </AgentPulseProvider>
  );
}
When an AI agent calls
expose_set
or
expose_call
, users see:
  • Animated cursor moving to the target element
  • Character-by-character typing for text inputs
  • Click ripple effects for button actions
AgentPulseProvider
中添加
VisualOverlay
tsx
import { AgentPulseProvider, VisualOverlay } from 'agentpulse';

function App() {
  return (
    <AgentPulseProvider endpoint="ws://localhost:3100/ws">
      <VisualOverlay />
      <MyApp />
    </AgentPulseProvider>
  );
}
当AI Agent调用
expose_set
expose_call
时,用户将看到:
  • 动画光标移动到目标元素
  • 文本输入的逐字打字效果
  • 按钮操作的点击波纹效果

Configuration

配置选项

tsx
<VisualOverlay
  enabled={true}           // Master toggle (default: true)
  cursor={true}            // Show AI cursor (default: true)
  clickRipple={true}       // Show click effects (default: true)
  typingAnimation={true}   // Character-by-character typing (default: true)
  typingSpeed={12}         // Characters per second (default: 12)
/>
tsx
<VisualOverlay
  enabled={true}           // 全局开关(默认值:true)
  cursor={true}            // 显示AI光标(默认值:true)
  clickRipple={true}       // 显示点击效果(默认值:true)
  typingAnimation={true}   // 逐字打字动画(默认值:true)
  typingSpeed={12}         // 每秒输入字符数(默认值:12)
/>

Element Targeting

元素定位

The overlay finds elements using
data-agentpulse-id
attributes.
覆盖层通过
data-agentpulse-id
属性查找元素。

Naming Convention

命名规范

Format:
data-agentpulse-id="componentId-normalizedKey"
Where
normalizedKey
= binding key with
set
prefix removed, lowercased.
BindingNormalized KeyAttribute
setName
name
data-agentpulse-id="form-name"
setEmail
email
data-agentpulse-id="form-email"
submitForm
submitform
data-agentpulse-id="form-submitform"
setValue
value
data-agentpulse-id="input-value"
格式:
data-agentpulse-id="componentId-normalizedKey"
其中
normalizedKey
= 绑定键移除
set
前缀后,转换为小写。
绑定方法标准化键属性值
setName
name
data-agentpulse-id="form-name"
setEmail
email
data-agentpulse-id="form-email"
submitForm
submitform
data-agentpulse-id="form-submitform"
setValue
value
data-agentpulse-id="input-value"

Example

示例

tsx
function ContactForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  useExpose('contact-form', {
    setName: (v) => setName(v),
    setEmail: (v) => setEmail(v),
    submitForm: () => handleSubmit(),
  });

  return (
    <form>
      <input data-agentpulse-id="contact-form-name" value={name} />
      <input data-agentpulse-id="contact-form-email" value={email} />
      <button data-agentpulse-id="contact-form-submitform">Submit</button>
    </form>
  );
}
tsx
function ContactForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  useExpose('contact-form', {
    setName: (v) => setName(v),
    setEmail: (v) => setEmail(v),
    submitForm: () => handleSubmit(),
  });

  return (
    <form>
      <input data-agentpulse-id="contact-form-name" value={name} />
      <input data-agentpulse-id="contact-form-email" value={email} />
      <button data-agentpulse-id="contact-form-submitform">Submit</button>
    </form>
  );
}

Auto-Discovery Fallback Chain

自动发现回退机制

If
data-agentpulse-id
is missing, the resolver tries (in order):
  1. [data-agentpulse-id="componentId-normalizedKey"]
  2. Form container
    [data-agentpulse-id="componentId"]
    → input by name
  3. input[name="key"]
    or
    textarea[name="key"]
  4. getElementById(key)
    or
    getElementById("componentId-key")
  5. input[placeholder*="key"]
    (case-insensitive)
  6. [aria-label*="key"]
    (case-insensitive)
  7. Submit button detection for
    submitForm
    actions
  8. Open/close button detection for modal actions
如果缺少
data-agentpulse-id
属性,解析器会按以下顺序尝试查找:
  1. [data-agentpulse-id="componentId-normalizedKey"]
  2. 表单容器
    [data-agentpulse-id="componentId"]
    → 通过name查找输入框
  3. input[name="key"]
    textarea[name="key"]
  4. getElementById(key)
    getElementById("componentId-key")
  5. input[placeholder*="key"]
    (不区分大小写)
  6. [aria-label*="key"]
    (不区分大小写)
  7. submitForm
    操作检测提交按钮
  8. 为模态框操作检测打开/关闭按钮

Custom CSS Selectors

自定义CSS选择器

For complex layouts where auto-discovery fails:
tsx
<VisualOverlay
  targets={{
    'contact-form': {
      name: 'input[name="fullName"]',
      email: 'input[type="email"]',
      submit: 'button[type="submit"]',
    },
    'sidebar': {
      toggle: '#sidebar-toggle',
    },
  }}
/>
Or configure programmatically:
tsx
import { setAnimationConfig, clearAnimationConfig } from 'agentpulse';

setAnimationConfig({
  'my-form': {
    username: '#username-input',
    password: '#password-input',
  },
});

// Clear when done
clearAnimationConfig();
对于自动发现失败的复杂布局:
tsx
<VisualOverlay
  targets={{
    'contact-form': {
      name: 'input[name="fullName"]',
      email: 'input[type="email"]',
      submit: 'button[type="submit"]',
    },
    'sidebar': {
      toggle: '#sidebar-toggle',
    },
  }}
/>
或者通过编程方式配置:
tsx
import { setAnimationConfig, clearAnimationConfig } from 'agentpulse';

setAnimationConfig({
  'my-form': {
    username: '#username-input',
    password: '#password-input',
  },
});

// 使用完毕后清除
clearAnimationConfig();

Common Patterns

常见模式

Form with Multiple Fields

多字段表单

tsx
useExpose('signup-form', {
  setEmail: (v) => setEmail(v),
  setPassword: (v) => setPassword(v),
  submit: () => handleSubmit(),
});

// Add data attributes to each input
<input data-agentpulse-id="signup-form-email" />
<input data-agentpulse-id="signup-form-password" />
<button data-agentpulse-id="signup-form-submit">Sign Up</button>
tsx
useExpose('signup-form', {
  setEmail: (v) => setEmail(v),
  setPassword: (v) => setPassword(v),
  submit: () => handleSubmit(),
});

// 为每个输入框添加数据属性
<input data-agentpulse-id="signup-form-email" />
<input data-agentpulse-id="signup-form-password" />
<button data-agentpulse-id="signup-form-submit">Sign Up</button>

Third-Party Component Libraries

第三方组件库

For MUI, Chakra, etc., wrap or pass the data attribute:
tsx
// MUI TextField
<TextField
  inputProps={{ 'data-agentpulse-id': 'form-email' }}
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

// Or use CSS selector config
<VisualOverlay
  targets={{
    'form': {
      email: '.MuiTextField-root input',
    },
  }}
/>
对于MUI、Chakra等组件库,可包裹组件或传递数据属性:
tsx
// MUI TextField
<TextField
  inputProps={{ 'data-agentpulse-id': 'form-email' }}
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

// 或使用CSS选择器配置
<VisualOverlay
  targets={{
    'form': {
      email: '.MuiTextField-root input',
    },
  }}
/>

Search Box

搜索框

tsx
useExpose('search', {
  query,
  setQuery,
  search: () => performSearch(),
});

<input data-agentpulse-id="search-query" />
<button data-agentpulse-id="search-search">Search</button>
tsx
useExpose('search', {
  query,
  setQuery,
  search: () => performSearch(),
});

<input data-agentpulse-id="search-query" />
<button data-agentpulse-id="search-search">Search</button>

Troubleshooting

故障排除

IssueCauseSolution
Cursor goes to wrong elementKey mismatchCheck normalized key matches attribute
No animation on actionMissing attributeAdd
data-agentpulse-id
to element
Animation on wrong form fieldDuplicate attributesMake each attribute unique per component
Third-party input not foundNested DOM structureUse CSS selector config
问题原因解决方案
光标指向错误元素键不匹配检查标准化键是否与属性值匹配
操作时无动画缺少属性为元素添加
data-agentpulse-id
错误的表单字段触发动画属性重复确保每个组件的属性值唯一
第三方输入框未被找到DOM结构嵌套使用CSS选择器配置

Debug Targeting

调试定位

Open browser console and look for resolver logs:
[TargetResolver] Found element for contact-form.name using selector: ...
[TargetResolver] Auto-discovered element for contact-form.email
[TargetResolver] No element found for contact-form.phone
打开浏览器控制台,查看解析器日志:
[TargetResolver] Found element for contact-form.name using selector: ...
[TargetResolver] Auto-discovered element for contact-form.email
[TargetResolver] No element found for contact-form.phone

Process

实施步骤

  1. Add VisualOverlay - Import and add inside AgentPulseProvider
  2. Identify target elements - Which inputs/buttons need animations?
  3. Add data attributes - Use
    data-agentpulse-id="componentId-normalizedKey"
  4. Test with agent - Call
    expose_set
    or
    expose_call
    and verify animations
  5. Configure fallbacks - Use CSS selectors for complex layouts
  1. 添加VisualOverlay - 导入并在AgentPulseProvider中添加该组件
  2. 确定目标元素 - 哪些输入框/按钮需要添加动画?
  3. 添加数据属性 - 使用
    data-agentpulse-id="componentId-normalizedKey"
    格式
  4. 与Agent配合测试 - 调用
    expose_set
    expose_call
    并验证动画效果
  5. 配置回退方案 - 为复杂布局使用CSS选择器

More Details

更多详情

See
references/TARGETING_PATTERNS.md
for:
  • Full fallback chain explanation
  • Naming convention edge cases
  • Third-party component strategies
  • Debug techniques
请查看
references/TARGETING_PATTERNS.md
了解:
  • 完整的回退机制说明
  • 命名规范的边缘情况
  • 第三方组件的适配策略
  • 调试技巧