> ## Documentation Index
> Fetch the complete documentation index at: https://docs.profy.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 可视化

> profy-visualize：把数据、3D 场景、结构化界面直接渲染进对话，并带自检工具验证渲染结果

# 可视化（profy-visualize）

## 一句话定义

`profy-visualize` 让专家**把可视化结果直接画在对话里**——图表、3D 展品、地理地图、交互式界面——而不是给你一段代码或一张静态图片。产出是可交互的（能悬停、能旋转、能点击），并且平台提供了配套的自检工具让模型在给你看之前先验证渲染有没有出问题。

## 激活条件

| 字段                | 取值                                                   |
| ----------------- | ---------------------------------------------------- |
| 插件 ID             | `profy-visualize`                                    |
| `user_selectable` | `true`——**在插件面板里手动勾选**                               |
| `conditions`      | `{ "sandbox_mode": "!none" }`（需要沙箱，非 `none` 模式）      |
| 注入工具              | `visualize` / `inspect_3d` / `render_ui` / `browser` |
| 注入提示词             | `VISUALIZE.md` / `3D.md` / `DATA_VIZ.md` / `A2UI.md` |
| 声明技能              | 8 篇（目录下另有 14 篇可按需加载，见下）                              |

<Note>
  `browser` 工具是**故意被这个插件一起绑定**的：视觉校验流程要调 `browser(action='screenshot')`，如果你只勾了 Visualize 而没有浏览器能力，提示词里引用的工具就不存在，自检环节会整个失效。这也是为什么单独勾选 Visualize 时你会看到浏览器工具也被激活。
</Note>

## 三个渲染工具怎么选

这是使用这个插件时唯一需要理解的判断，其余都是模型的事。

| 工具           | 产出                       | 用在什么场合                       |
| ------------ | ------------------------ | ---------------------------- |
| `visualize`  | 沙箱 iframe 里的 HTML/CSS/JS | 定制视觉：图表、3D、动画、模拟             |
| `render_ui`  | 原生 React 组件（A2UI）        | 布局 + 数据 + 操作：卡片、表格、价格对比、状态面板 |
| `inspect_3d` | 结构化诊断 JSON               | 不产出画面，用来检查 Three.js 场景健康度    |

判断口诀写在提示词里：**输出是「布局 + 数据 + 动作」用 `render_ui`，输出是「自定义画面」用 `visualize`**。

两者最实际的差别在于观感一致性：`render_ui` 渲染出来的东西和 Profy 界面本身是同一套设计系统（因为就是同一批 React 组件），而 `visualize` 是 iframe 里的独立世界，好看与否完全取决于模型写的 CSS。所以做「一张对比表」用 `render_ui` 会比让模型手写 HTML 表格稳定得多。

***

## visualize：内联 HTML 可视化

### 参数

| 参数      | 类型     | 必填 | 说明                                  |
| ------- | ------ | -- | ----------------------------------- |
| `title` | string | 是  | 可视化的简短标题                            |
| `html`  | string | 是  | HTML 片段，可含内联 `<script>` 与 `<style>` |
| `css`   | string | 否  | 额外注入的 CSS                           |

### 沙箱与网络

渲染发生在 **sandboxed iframe** 里，默认无网络访问。但 CDN 是放行的——这是唯一的例外，因为几乎所有可视化库都靠 CDN 引入。已验证可用的源：

```
https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js
https://cdn.jsdelivr.net/npm/d3@7/+esm
https://cdn.jsdelivr.net/npm/vega-lite@5/+esm
https://cdn.jsdelivr.net/npm/vega-embed@6/+esm
https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm
```

jsdelivr / unpkg / cdnjs 三个域名放行，其他外部请求会被 iframe 沙箱拦掉。**这意味着可视化不能实时拉你的 API 数据**——数据必须由模型内联进 HTML。对于几百行的数据集这没问题，几万行就需要先在沙箱里聚合再内联。

### 设计规范（提示词层强制）

模型被要求遵守六条：

1. **自包含**：所有东西在一个 HTML 片段里，不引用外部文件
2. **响应式**：`width: 100%`，高度典型值 400–600px
3. **明暗自适应**：用 `color-scheme: light dark` 或 `prefers-color-scheme`
4. **可交互**：该有悬停提示、点击、缩放平移的地方要有
5. **可访问**：关键元素带 ARIA 标签
6. **性能**：DOM 元素控制在 1000 以内，大数据集走 canvas/WebGL

第 6 条是实践中最容易撞的：用 `<div>` 画一万个点的散点图会让页面卡死，必须换 canvas。

### 视觉自检循环（这个插件最有价值的部分）

提示词里写死了一套「Vision in the Loop」协议——模型**在把结果给你看之前**必须先自己看一眼：

<Steps>
  <Step title="生成或修改代码">
    写出 HTML 片段
  </Step>

  <Step title="截图">
    `browser(action="screenshot", html=<your_html>)`
  </Step>

  <Step title="读图">
    `image(action="read", image_urls=[...], prompt="检查渲染、构图、标签、可见错误")`
  </Step>

  <Step title="自己分析">
    按症状对照：画布全白 → WebGL 上下文错误或脚本报错；元素缺失 → 几何/材质/光照问题；布局错位 → 相机或位置缩放；坐标轴没了 → scale domain 或 append 顺序；数据没渲染 → 数据绑定或解析错误
  </Step>

  <Step title="有问题就回到第 1 步">
    修完重新截图，直到看起来对了才呈现给用户
  </Step>
</Steps>

这条协议是这个插件与「让模型直接写个图表」之间的核心差别。没有它，模型交付的是**它认为应该长成的样子**；有了它，交付的是**它确认真的长成的样子**。

***

## render\_ui：声明式原生界面（A2UI）

### 参数

| 参数           | 类型     | 必填 | 说明                       |
| ------------ | ------ | -- | ------------------------ |
| `components` | array  | 是  | A2UI 组件定义数组，每个必须有 `type` |
| `surface_id` | string | 否  | 稳定的界面标识，省略则自动生成 uuid4    |

协议版本固定为 `0.9.1`。

### 组件类型

`Card` / `Row` / `Column` / `Text` / `Button` / `Image` / `Table` / `PricingTable`，可通过 `children` 数组嵌套。

### 校验会先于渲染

每个组件（含所有层级的 children）都会被递归校验必须带 `type` 字段。校验不通过时返回的是错误详情而不是界面：

```json theme={null}
{
  "error": "Invalid component structure",
  "details": ["components[0].children[2]: missing required `type` field"]
}
```

错误信息带完整路径（`components[0].children[2]`），所以模型能精确定位问题。`children` 不是数组时也会被指出（`.children: must be an array`）。

<Info>
  `render_ui` 渲染的是**原生 React 组件**，不走 iframe。所以它没有 `visualize` 的网络限制问题，但也不能跑任意 JS——你只能用平台提供的组件类型。这是安全性与灵活性的取舍：能力上限低，但产出必然和产品设计系统一致。
</Info>

***

## inspect\_3d：Three.js 场景诊断

这个工具不产出画面，它回答「我刚渲染的 3D 场景到底健不健康」。

### 参数

| 参数                   | 默认   | 说明                                              |
| -------------------- | ---- | ----------------------------------------------- |
| `url`                | 无    | 检查前先导航到的 URL；省略则检查当前页（配合 `browser(set_html)` 用） |
| `max_depth`          | 5    | 场景树遍历最大深度                                       |
| `include_materials`  | true | 是否输出材质清单                                        |
| `include_animations` | true | 是否输出动画片段列表                                      |
| `performance_audit`  | true | 是否输出性能报告与告警                                     |

### 前提：场景必须被暴露出来

工具通过 CDP 注入 JS 遍历场景图，页面必须把场景挂在 `window.__THREE_SCENE__` 或 `window.scene` 上。没挂就会拿到：

```
Three.js scene not found. Expose via window.__THREE_SCENE__ or window.scene
```

这不是 bug 而是契约——写 Three.js 代码时顺手加一行 `window.__THREE_SCENE__ = scene;` 就能让整个诊断链路可用。

### 它会告诉你什么

| 告警                                    | 触发条件               | 含义                   |
| ------------------------------------- | ------------------ | -------------------- |
| `WebGL not available`                 | 拿不到 WebGL 上下文      | 环境问题，画面必然全白          |
| `WebGL error on active canvas: <err>` | canvas 上有 WebGL 错误 | 着色器/纹理/缓冲区出错         |
| `Three.js scene not found...`         | 场景未暴露              | 加一行全局赋值              |
| `High triangle count: <n>`            | 三角面 > 1,000,000    | 需要减面或用 LOD           |
| `High draw calls: <n>`                | draw call > 100    | 需要合并几何体或用 instancing |

「画面全白」这个症状在 3D 里非常常见且难以从截图判断原因——可能是 WebGL 挂了、可能是相机看错方向、可能是场景根本没物体。`inspect_3d` 的价值就是把这三种情况区分开。

### 双模式支持

沙箱模式走 CDP，桌面模式走 browser 工具路由，两边行为一致。解析失败时会返回 `{"raw_output": ..., "warnings": ["Could not parse inspection result as JSON"]}` 而不是抛错，所以拿到 `raw_output` 说明注入执行了但输出格式异常。

***

## 技能层

manifest 显式声明 8 篇技能，这 8 篇的**正文会被注入进提示词**：

`visualize` / `threejs-showcase` / `molecular-visualization` / `data-visualization` / `d3-data-visualization` / `geospatial-visualization` / `statistical-visualization` / `a2ui-patterns`

但插件目录下实际有 **22 个技能目录**。平台的技能注册表会递归扫描 `plugins/builtin/*/skills/` 下所有 `SKILL.md`，所以另外 14 篇同样能通过 `skill` 工具按名加载，只是不会默认占用上下文：

`3d-data-visualization` / `accessibility-visualization` / `canvas2d-data-visualization` / `dashboards-realtime` / `gantt-chart` / `grammar-of-graphics` / `interactive-3d-atlas` / `node-link-diagram` / `react-nextjs-visualization` / `reports-pdf-slides` / `scrollytelling` / `threejs-data-visualization` / `uml-architecture` / `visualization-strategy`

<Note>
  这是一条通用规律，不止 visualize：**manifest 的 `skills` 列表 = 默认注入的**，**目录里的 SKILL.md = 可按需加载的**。前者花上下文买确定性，后者省上下文但需要模型主动去取。所以你说「用甘特图展示排期」时模型会先去加载 `gantt-chart` 再动手，中间那一步不是它在磨蹭。
</Note>

## 可执行示例

<AccordionGroup>
  <Accordion title="数据图表">
    ```
    这是我们过去 12 个月的营收和成本数据（贴表格），
    画一张双轴图，营收用柱状、成本用折线，悬停显示具体数值和当月利润率。
    ```

    模型会选 `visualize` + D3 或 Vega-Lite，画完截图自检，确认坐标轴和悬停都正常后再给你。
  </Accordion>

  <Accordion title="3D 产品展示">
    ```
    做一个可以拖拽旋转的产品展台，展示一个圆角立方体，
    带环境光和一盏主光，底部有阴影。要能看清材质质感。
    ```

    这类需求会触发 `3D.md` 提示词与 `threejs-showcase` 技能，并在渲染后调 `inspect_3d` 确认 draw call 和三角面在合理范围。
  </Accordion>

  <Accordion title="结构化对比界面">
    ```
    把这三个方案做成一张对比卡片，每个方案列出价格、适用规模、三条核心能力，
    最下面各放一个「选择这个」按钮。
    ```

    这是 `render_ui` 的典型场景——布局 + 数据 + 动作，不需要自定义画面。
  </Accordion>

  <Accordion title="地理数据">
    ```
    用这份省份销售数据画一张中国地图分级填色图，
    颜色按销售额分五档，鼠标悬停显示省份名和金额。
    ```

    会加载 `geospatial-visualization` 技能。
  </Accordion>
</AccordionGroup>

## 边界与失败态

| 症状                            | 原因                             | 处理                        |
| ----------------------------- | ------------------------------ | ------------------------- |
| 可视化区域一片空白                     | iframe 里脚本报错，或 CDN 被拦          | 让模型截图自检；确认用的是放行的三个 CDN 域名 |
| 3D 场景全黑                       | WebGL 上下文失败或相机方向错              | 让模型跑 `inspect_3d` 区分这两种情况 |
| `Three.js scene not found`    | 页面没暴露 `window.__THREE_SCENE__` | 让模型加一行全局赋值后重新检查           |
| `Invalid component structure` | `render_ui` 的组件缺 `type`        | 错误详情里有精确路径，让模型按路径修        |
| 图表卡顿、浏览器发烫                    | DOM 元素超过 1000，用 div 画了大数据      | 明确要求「用 canvas 渲染」         |
| 可视化里的数据是编的                    | 你没提供数据，模型只能造示例                 | 把真实数据贴进对话，或让它先从文件读        |
| 插件面板里勾了但没生效                   | `sandbox_mode` 为 `none`        | 这个插件需要沙箱，检查对话是否在无沙箱模式     |

<Warning>
  **可视化不能实时连你的数据源。** iframe 无网络（CDN 除外），所以图里的数据是生成那一刻内联进去的快照。要"活"的看板需要走 Sites 发布一个真站点，而不是内联可视化。
</Warning>

## 验证

<Steps>
  <Step title="确认插件已激活">
    问「你现在能在对话里直接画图吗？」。激活时专家会区分 `visualize` 与 `render_ui` 两种产出；未激活时它会说"我可以给你代码"。
  </Step>

  <Step title="最小图表">
    「用 \[1,3,2,5,4] 画一个柱状图」。应该直接看到可交互图表，不是代码块。
  </Step>

  <Step title="验证自检生效">
    提一个稍复杂的 3D 需求，观察模型是否在给你结果前调用了截图与 `inspect_3d`。跳过自检直接交付的，多半是浏览器工具没绑上。
  </Step>
</Steps>

## 相关页面

<CardGroup cols={2}>
  <Card title="渲染表面" icon="layout" href="/zh/documentation/plugins/rendering-surfaces">
    对话里各类渲染表面的总览与区别
  </Card>

  <Card title="A2UI" icon="component" href="/zh/documentation/plugins/a2ui">
    声明式界面协议的组件与模式
  </Card>

  <Card title="3D 开发" icon="box" href="/zh/documentation/plugins/3d-development">
    Blender / Godot 桥接与 3D 资产管线
  </Card>

  <Card title="画布" icon="pen-tool" href="/zh/documentation/capabilities/canvas">
    自由创作画布（与内联可视化正交）
  </Card>
</CardGroup>

<Note>
  核对日期 2026-08-11。来源：`services/agent-runtime/src/plugins/builtin/visualize/plugin.json`、`tools/{visualize,render_ui,inspect_3d,_inspect_runner}.py`、`prompts/VISUALIZE.md`、`services/agent-runtime/src/skills/registry.py`。
</Note>
