Skip to main content

Visualize (profy-visualize)

One-line definition

profy-visualize lets an expert draw the result directly into the conversation — charts, 3D exhibits, geographic maps, interactive interfaces — instead of handing you code or a static image. The output is interactive (hover, rotate, click), and the plugin ships a companion inspection tool so the model can verify the render before showing it to you.

Activation

The browser tool is deliberately bound by this plugin: the visual verification loop calls browser(action='screenshot'). If you ticked Visualize without browser capability, the tool referenced by the prompt would not exist and the entire self-check step would silently fail. That is why ticking Visualize alone also lights up the browser tool.

Choosing among the three rendering tools

This is the only judgement you need to make; the rest is the model’s job. The rule of thumb is written into the prompt: if the output is “layout + data + actions” use render_ui; if it is a “custom visual” use visualize. The practical difference is visual consistency. render_ui output uses the same design system as Profy itself (literally the same React components), while visualize is an independent world inside an iframe whose appearance depends entirely on the CSS the model wrote. So for something like a comparison table, render_ui is far more reliable than asking the model to hand-write an HTML table.

visualize: inline HTML visualization

Parameters

Sandbox and network

Rendering happens inside a sandboxed iframe with no network access by default. CDNs are the one exception, because virtually every visualization library is loaded that way. Verified sources:
jsdelivr, unpkg, and cdnjs are allowed; other outbound requests are blocked by the iframe sandbox. This means a visualization cannot pull live data from your API — the data must be inlined into the HTML by the model. For a few hundred rows that is fine; for tens of thousands, aggregate in the sandbox first, then inline the result.

Design rules (enforced at the prompt layer)

The model is held to six:
  1. Self-contained — everything in one HTML fragment, no external file references
  2. Responsivewidth: 100%, typical heights 400–600px
  3. Light/dark adaptivecolor-scheme: light dark or prefers-color-scheme
  4. Interactive — hover tooltips, click handlers, zoom/pan where appropriate
  5. Accessible — ARIA labels on key elements
  6. Performant — keep DOM elements under 1,000; use canvas/WebGL for large datasets
Rule 6 is the one most often violated in practice: a scatter plot of ten thousand points drawn with <div> elements will lock up the page. Canvas is mandatory at that scale.

The visual self-check loop (the most valuable part of this plugin)

The prompt hard-codes a “Vision in the Loop” protocol — the model must look at its own output before showing it to you:
1

Generate or modify code

Write the HTML fragment.
2

Capture

browser(action="screenshot", html=<your_html>)
3

Read the image

image(action="read", image_urls=[...], prompt="Check rendering, composition, labels, and visible errors")
4

Diagnose by symptom

Blank canvas → WebGL context error or script error. Missing elements → geometry/material/lighting. Wrong layout → camera, position, or scale. Missing axes → scale domain or append order. No data rendered → data binding or parse error.
5

Loop on any issue

Fix and re-capture until it looks right, only then present it.
This protocol is the core difference between this plugin and simply asking a model to write a chart. Without it, what you receive is what the model believes the output should look like. With it, what you receive is what it confirmed the output actually looks like.

render_ui: declarative native UI (A2UI)

Parameters

Protocol version is pinned at 0.9.1.

Component types

Card / Row / Column / Text / Button / Image / Table / PricingTable, nestable through a children array.

Validation precedes rendering

Every component — at every nesting level — is recursively validated for a type field. On failure you get error detail rather than a surface:
The error carries a full path (components[0].children[2]), so the model can locate the problem exactly. A non-array children is also called out (.children: must be an array).
render_ui renders native React components, not an iframe. It therefore has none of visualize’s network constraints — but it also cannot run arbitrary JS. You are limited to the component types the platform provides. That is the safety/flexibility trade: a lower ceiling, but output that necessarily matches the product’s design system.

inspect_3d: Three.js scene diagnostics

This tool produces no visual. It answers “is the 3D scene I just rendered actually healthy?”

Parameters

Prerequisite: the scene must be exposed

The tool injects JS via CDP to traverse the scene graph, so the page must expose the scene on window.__THREE_SCENE__ or window.scene. Without it you get:
This is a contract, not a bug — adding one line, window.__THREE_SCENE__ = scene;, unlocks the whole diagnostic chain.

What it reports

“Blank canvas” is an extremely common 3D symptom and impossible to diagnose from a screenshot alone — WebGL may have died, the camera may be pointing the wrong way, or the scene may genuinely be empty. Distinguishing those three is exactly what inspect_3d is for.

Dual mode

Sandbox mode goes through CDP; desktop mode routes via the browser tool. Behavior is identical. When the injected result cannot be parsed, the tool returns {"raw_output": ..., "warnings": ["Could not parse inspection result as JSON"]} rather than raising — so a raw_output payload means injection ran but the output shape was unexpected.

Skills

The manifest declares 8 skills whose full text is injected into the prompt: visualize / threejs-showcase / molecular-visualization / data-visualization / d3-data-visualization / geospatial-visualization / statistical-visualization / a2ui-patterns The plugin directory, however, contains 22 skill directories. The platform’s skill registry recursively scans every SKILL.md under plugins/builtin/*/skills/, so the other 14 are equally loadable by name through the skill tool — they just do not occupy context by default: 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
This pattern is general, not specific to Visualize: the manifest’s skills list is what gets injected by default, while every SKILL.md in the directory is loadable on demand. The former spends context to buy certainty; the latter saves context but requires the model to fetch it. So when you ask for “a Gantt chart of the schedule” and the model loads gantt-chart before doing anything, that intermediate step is not stalling.

Executable examples

The model picks visualize with D3 or Vega-Lite, screenshots its own output, confirms the axes and hover work, and only then presents it.
This triggers the 3D.md prompt and the threejs-showcase skill, then calls inspect_3d to confirm draw calls and triangle count are sane.
Classic render_ui territory: layout plus data plus actions, no bespoke visual needed.
Loads the geospatial-visualization skill.

Boundaries and failure modes

Visualizations cannot connect to your live data source. The iframe has no network access beyond CDNs, so the data in a chart is a snapshot inlined at generation time. A genuinely live dashboard needs a real site published through Sites, not an inline visualization.

Verify

1

Confirm activation

Ask “can you draw charts directly in this conversation?” When active, the expert distinguishes visualize from render_ui output; when inactive it offers to give you code.
2

Minimal chart

“Draw a bar chart of [1,3,2,5,4].” You should see an interactive chart, not a code block.
3

Confirm self-check runs

Give it a moderately complex 3D request and watch for a screenshot and inspect_3d call before delivery. Skipping straight to delivery usually means the browser tool was not bound.

Rendering surfaces

Overview of the in-chat rendering surfaces and how they differ

A2UI

Components and patterns of the declarative UI protocol

3D development

Blender / Godot bridges and the 3D asset pipeline

Canvas

The free-form creation canvas (orthogonal to inline visualization)
Verified 2026-08-11. Sources: 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.