<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shahriar M Abu Hena</title>
    <description>The latest articles on DEV Community by Shahriar M Abu Hena (@imshaikot).</description>
    <link>https://dev.to/imshaikot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4091366%2F8779c24b-b16a-446d-9f4f-e253d39dcd00.jpg</url>
      <title>DEV Community: Shahriar M Abu Hena</title>
      <link>https://dev.to/imshaikot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imshaikot"/>
    <language>en</language>
    <item>
      <title>Claude in Chrome vs Playwright MCP Extension vs Browsentic: who gets to touch your logged-in browser?</title>
      <dc:creator>Shahriar M Abu Hena</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:40:40 +0000</pubDate>
      <link>https://dev.to/imshaikot/claude-in-chrome-vs-playwright-mcp-extension-vs-browsentic-who-gets-to-touch-your-logged-in-31nb</link>
      <guid>https://dev.to/imshaikot/claude-in-chrome-vs-playwright-mcp-extension-vs-browsentic-who-gets-to-touch-your-logged-in-31nb</guid>
      <description>&lt;p&gt;Headless browsers were never the point. The point was always the tab you are already logged into: the admin dashboard with no API, the vendor portal from 2011, the Google Doc your manager keeps asking you to update. Three tools now let an AI agent drive &lt;em&gt;that&lt;/em&gt; tab instead of a fresh Chromium in a sandbox.&lt;/p&gt;

&lt;p&gt;I built one of them. &lt;strong&gt;Browsentic is mine. Discount accordingly.&lt;/strong&gt; I have tried to hold it to the same bar as the other two, because a comparison that flatters the author is worth exactly what you paid for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Claude in Chrome&lt;/th&gt;
&lt;th&gt;Playwright MCP Extension&lt;/th&gt;
&lt;th&gt;Browsentic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;A product&lt;/td&gt;
&lt;td&gt;A bridge&lt;/td&gt;
&lt;td&gt;A side panel plus a local daemon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who runs the model&lt;/td&gt;
&lt;td&gt;Anthropic's cloud&lt;/td&gt;
&lt;td&gt;Whatever MCP client you attach&lt;/td&gt;
&lt;td&gt;Whatever agent CLI you already have (Claude Code, Codex, Antigravity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;Paid Claude plan, from $20/mo&lt;/td&gt;
&lt;td&gt;Free (Apache 2.0)&lt;/td&gt;
&lt;td&gt;Free (MIT), no second bill on top of the agent you have&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;Chrome Web Store&lt;/td&gt;
&lt;td&gt;Chrome Web Store + &lt;code&gt;npx @playwright/mcp --extension&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npx browsentic setup&lt;/code&gt;, then Load unpacked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where you talk to it&lt;/td&gt;
&lt;td&gt;Side panel, or your terminal via &lt;code&gt;claude --chrome&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Your terminal or IDE&lt;/td&gt;
&lt;td&gt;Side panel, or any MCP client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approves risky actions&lt;/td&gt;
&lt;td&gt;Classifiers decide; "automatically approve" is a default in Cowork&lt;/td&gt;
&lt;td&gt;Only the generic prompt your MCP client shows&lt;/td&gt;
&lt;td&gt;Declarative policy; forms, downloads, off-scope navigation ask first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runs arbitrary JS&lt;/td&gt;
&lt;td&gt;Yes, internally&lt;/td&gt;
&lt;td&gt;Yes, &lt;code&gt;browser_evaluate&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Off by default; you read the code before it runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browsers&lt;/td&gt;
&lt;td&gt;Chrome, Edge, other Chromium&lt;/td&gt;
&lt;td&gt;Chrome, Edge&lt;/td&gt;
&lt;td&gt;Chrome, Edge, Brave, Arc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data leaves your machine&lt;/td&gt;
&lt;td&gt;Yes, to Anthropic&lt;/td&gt;
&lt;td&gt;Only what your MCP client sends&lt;/td&gt;
&lt;td&gt;Only what your agent CLI sends&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every row has a catch. Let's go through them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude in Chrome: the polished one with a cloud in the loop
&lt;/h2&gt;

&lt;p&gt;Anthropic's extension &lt;a href="https://gigazine.net/gsc_news/en/20260827-claude-chrome-available/" rel="noopener noreferrer"&gt;went generally available on August 26, 2026&lt;/a&gt; for every paid Claude plan. You install it from the Web Store, sign in, and a Claude side panel appears beside your tab. It reads pages, clicks, fills forms, records GIFs of what it did. If you use Claude Code, &lt;code&gt;claude --chrome&lt;/code&gt; wires the same extension to your terminal and shares your browser's login state.&lt;/p&gt;

&lt;p&gt;It is the smoothest of the three by a wide margin. Zero setup. A real design team. Two prompt-injection classifiers, one on incoming content and one on actions before they execute, plus a blocklist for financial, adult and piracy sites and a hard "no" on stock trades, CAPTCHAs and facial images. Nobody else on this list ships a classifier.&lt;/p&gt;

&lt;p&gt;Now the catches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You rent it.&lt;/strong&gt; Pro, Max, Team or Enterprise, or nothing. If your Claude Code authenticates with an API key, a long-lived token, Bedrock, Vertex or Foundry, Chrome integration &lt;a href="https://code.claude.com/docs/en/chrome" rel="noopener noreferrer"&gt;stays off&lt;/a&gt;. One model family, one vendor, one bill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cloud is between you and your tab.&lt;/strong&gt; Page content goes up to Anthropic. The extension holds a connection to &lt;code&gt;bridge.claudeusercontent.com&lt;/code&gt;. That is fine for many people and a non-starter for anyone whose logged-in tabs contain customer data they are not allowed to ship to a third party.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It has already been popped once.&lt;/strong&gt; In December 2025, Koi Security disclosed &lt;a href="https://thehackernews.com/2026/03/claude-extension-flaw-enabled-zero.html" rel="noopener noreferrer"&gt;ShadowPrompt&lt;/a&gt;: an over-broad &lt;code&gt;*.claude.ai&lt;/code&gt; allowlist chained with a DOM XSS in a CAPTCHA component meant any website could inject prompts into the extension as if you had typed them. No click, no permission dialog. Fixed in 1.0.41. Every extension that holds the &lt;code&gt;debugger&lt;/code&gt; permission and talks to a cloud origin carries this class of risk, but this one has a CVE-shaped story attached to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A long list of Chrome permissions at install&lt;/strong&gt;, &lt;code&gt;debugger&lt;/code&gt; and &lt;code&gt;nativeMessaging&lt;/code&gt; among them, per Anthropic's own &lt;a href="https://support.claude.com/en/articles/12012173-getting-started-with-claude-in-chrome" rel="noopener noreferrer"&gt;getting-started guide&lt;/a&gt;. That is not unusual for this category, but you should know what you are handing over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Automatically approve" is a default mode.&lt;/strong&gt; Claude screens its own actions and pauses only when a classifier flags something. Anthropic's safety page says the risk "is not zero" and that you remain responsible for every action. A 2.8-star Web Store rating at GA suggests the beta did things people did not ask for.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pick it if:&lt;/em&gt; you already pay for Claude, you are fine with pages going to Anthropic, and you want the thing that works today with no terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright MCP Extension: the best page model, wearing no clothes
&lt;/h2&gt;

&lt;p&gt;Microsoft's Playwright MCP is the gold standard for how an agent should &lt;em&gt;see&lt;/em&gt; a page. It hands the model an accessibility-tree snapshot with stable element references, not pixels, so clicks land on &lt;code&gt;ref=e42&lt;/code&gt; rather than "the blue button near the top." Its &lt;code&gt;--extension&lt;/code&gt; flag plus the &lt;a href="https://chromewebstore.google.com/detail/playwright-extension/mmlmfjhmonkocbjadbfplnigmagldckm" rel="noopener noreferrer"&gt;Playwright MCP Bridge&lt;/a&gt; extension points that machinery at a tab in your real, logged-in Chrome or Edge. Free, Apache 2.0, works with Claude Code, Cursor, VS Code, Codex, anything that speaks MCP.&lt;/p&gt;

&lt;p&gt;If you are a QA engineer who wants to generate tests against an authenticated app, stop reading. This is your tool.&lt;/p&gt;

&lt;p&gt;For everyone else, the catches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is a bridge, not a product.&lt;/strong&gt; There is no UI. You type in a terminal, the browser moves, you alt-tab to see what happened. Every session begins with a tab-picker page. There is no timeline of what the agent did, no way to say "approve this once but not on that site."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safety is somebody else's problem.&lt;/strong&gt; &lt;code&gt;browser_evaluate&lt;/code&gt; runs arbitrary JavaScript in your logged-in tab, and the only thing standing in front of it is whatever generic "allow tool?" prompt your MCP client shows for every tool. There is no notion of scope, no "this run is about github.com, so navigating to evil.example should ask." The model reads raw page content with nothing telling it that content is data rather than instructions. Playwright was built for test runners, where the page is yours and hostile content is not the threat model. Pointed at the open web with your cookies, that assumption stops holding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chrome and Edge only in extension mode&lt;/strong&gt;, despite Playwright's cross-browser reputation. And the bridge has a reputation of its own: &lt;a href="https://github.com/microsoft/playwright-mcp/issues/1571" rel="noopener noreferrer"&gt;issues&lt;/a&gt; about the extension sitting at "No MCP clients are currently connected" while the server is demonstrably running are a recurring genre.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pick it if:&lt;/em&gt; you live in a terminal or IDE, you want the most precise page representation available, and you are comfortable being the entire safety layer yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browsentic: your agent, your browser, your rules
&lt;/h2&gt;

&lt;p&gt;Browsentic is a side panel plus a small local daemon. Open the panel beside any tab, type or dictate, and it drives the page. The model is whichever agent CLI you already have logged in: Claude Code, Codex or Antigravity, switchable with one click, and you pick the model each one runs. The same daemon doubles as an MCP server, so Cursor, Zed or Claude Desktop can drive the same browser. There is no Browsentic account and no Browsentic server. MIT, and the install path is one command.&lt;/p&gt;

&lt;p&gt;It is the only one of the three that does not decide which model you use, and the only one where the safety policy is a file on your disk rather than a promise.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Policy is data, not vibes.&lt;/strong&gt; Form submission, file upload, download, navigating off the sites a run is about, and typing a saved secret each pause with a card that names the rule. Allow once, deny, or "always on this host." Denies cannot be clicked past. A run's scope is derived from where it started and what you said, and nothing read from a page can widen it. Every rule is listed in the docs and every default can be changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live tools are off until you flip them on.&lt;/strong&gt; When the agent wants to write JavaScript for a page, the panel shows you the source and a Review button before a line of it runs. A script that worked can be kept, named after the site, and rerun by typing &lt;code&gt;/&lt;/code&gt;. There is deliberately no "always allow" for code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Point instead of describe.&lt;/strong&gt; Press the lens, hover, click. The element rides along with your next message. When the agent is the one who is unsure, it hands the lens back and asks you to point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It keeps working when you walk away.&lt;/strong&gt; Watch a build or an upload in the background, schedule something for ten minutes from now or every two, and it announces on the page you are looking at when it is done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teach it a site once.&lt;/strong&gt; It explores, writes reusable notes, and every later session already knows the way around. Record yourself doing a job once and later say "do it like last time."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page text is fenced.&lt;/strong&gt; Every block of page content is wrapped in a per-daemon random marker with a note that it is data, never instructions, and a run is confined to the sites it is about. Not a guarantee. The goal is that a successful injection has nowhere to send what it took.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two things to know before you install.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is not on the Chrome Web Store yet.&lt;/strong&gt; &lt;code&gt;npx browsentic setup&lt;/code&gt; installs the extension, starts the daemon and prints a pairing code. You then load the folder it printed through &lt;code&gt;chrome://extensions&lt;/code&gt; and paste the code. Two steps in the browser, once. Your browser stays paired through updates because the path never changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It runs the agent you bring.&lt;/strong&gt; You need Node 20 and one of Claude Code, Codex or Antigravity logged in. That is the trade: no second subscription, and no cloud between you and your tab, in exchange for a CLI on your machine. If you have none of the three, Claude in Chrome is the shorter road.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pick it if:&lt;/em&gt; you want the agent you already use, in a side panel, with a policy you can read and change, and nothing about your browser going anywhere your agent was not already sending it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The security paragraph everyone skips
&lt;/h2&gt;

&lt;p&gt;None of the three is immune to prompt injection, and any vendor who tells you otherwise is selling something. The honest differences are in what each one does &lt;em&gt;about&lt;/em&gt; it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude in Chrome&lt;/strong&gt; bets on classifiers and a blocklist. Strongest detection, weakest transparency. You do not see the rules and you cannot edit them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playwright MCP&lt;/strong&gt; bets on you. No detection, no scope, no fencing. Total transparency, because there is nothing to hide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browsentic&lt;/strong&gt; bets on containment. Fencing, scope, and gates on the actions that would exfiltrate. You can read every rule and change every default. A good enough page can still fool the model, and the design accepts that. The claim is that a fooled agent has nowhere to go.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick the failure mode you can live with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Already pay for Claude, want zero setup, do not mind the cloud:&lt;/strong&gt; Claude in Chrome. Turn off automatic approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test engineer, terminal-native, know exactly what &lt;code&gt;browser_evaluate&lt;/code&gt; can do:&lt;/strong&gt; Playwright MCP Extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Want a side panel, want to choose the agent, want the policy on your disk and your data off the cloud:&lt;/strong&gt; &lt;a href="https://github.com/imshaikot/browsentic" rel="noopener noreferrer"&gt;Browsentic&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try mine and it does something you did not ask for, open an issue. I read every one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>chrome</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How I got Claude Code, Cursor and Copilot to draw real architecture diagrams &amp; Bi-visuals</title>
      <dc:creator>Shahriar M Abu Hena</dc:creator>
      <pubDate>Mon, 24 Aug 2026 00:31:43 +0000</pubDate>
      <link>https://dev.to/imshaikot/how-i-got-claude-code-cursor-and-copilot-to-draw-real-architecture-diagrams-bi-visuals-263g</link>
      <guid>https://dev.to/imshaikot/how-i-got-claude-code-cursor-and-copilot-to-draw-real-architecture-diagrams-bi-visuals-263g</guid>
      <description>&lt;blockquote&gt;
&lt;h2&gt;
  
  
  An Agent Skill that renders diagrams, slides, social cards and animated sequence GIFs to PNG by authoring HTML and screenshotting it with headless Chrome. No design tool, no API, no npm dependencies.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask your coding agent for an architecture diagram. Go on, try it right now.&lt;/p&gt;

&lt;p&gt;You will get ASCII art. Or a Mermaid block that renders as three grey boxes with the labels overlapping. Or, if the model is feeling honest, a paragraph describing what the diagram &lt;em&gt;would&lt;/em&gt; look like if it could draw one.&lt;/p&gt;

&lt;p&gt;Your agent can write a parser, refactor a service and explain a race condition it has never seen before. It cannot draw a rectangle.&lt;/p&gt;

&lt;p&gt;That gap bothered me enough to close it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszgbqunb1z9ccwdztzb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszgbqunb1z9ccwdztzb9.png" alt="A rendered architecture diagram: nodes, labelled arrows, a return path" width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That diagram was not drawn in Figma. My agent wrote an HTML file and a script screenshotted it. So did every other image in this post, including the cover.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/imshaikot/render-visual-skill" rel="noopener noreferrer"&gt;render-visual&lt;/a&gt; is an &lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;Agent Skill&lt;/a&gt;: a folder of instructions and scripts that any skills-compatible agent can load. Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI, OpenCode, Amp and Goose all read the same format.&lt;/p&gt;

&lt;p&gt;Once it is installed you stop asking for code and start asking for pictures:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"make a diagram of our auth flow"&lt;br&gt;
"turn these notes into a 6-slide deck, paper theme"&lt;br&gt;
"an og card for this repo"&lt;br&gt;
"put this screenshot in a browser frame"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thirteen templates ship with it: architecture diagrams, swimlanes, trees, cluster diagrams, deployment diagrams, mind maps, sequence diagrams (static or animated), code windows, slides at 1920x1080, and social cards at 1200x630.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in about thirty seconds
&lt;/h2&gt;

&lt;p&gt;You need Node 18 or newer and any Chromium based browser. Chrome, Chromium, Brave and Edge all work, and you almost certainly have one already.&lt;/p&gt;

&lt;p&gt;For Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add imshaikot/render-visual-skill
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;render-visual-skill@render-visual-skill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For everything else, clone the published skill branch straight into your skills folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="nt"&gt;-b&lt;/span&gt; skill https://github.com/imshaikot/render-visual-skill.git &lt;span class="se"&gt;\&lt;/span&gt;
  ~/.agents/skills/render-visual
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole install. There is no npm install step, because there are no dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The pipeline is deliberately boring, which is the point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6dbw93jf9z7pwm4358sw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6dbw93jf9z7pwm4358sw.png" alt="The render pipeline: your ask, HTML, prepare, Chrome, verify, PNG, with two failure paths" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
Your agent copies a template, replaces the placeholder content, and runs one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node ~/.agents/skills/render-visual/scripts/render.mjs figure.html figure.png &lt;span class="nt"&gt;--theme&lt;/span&gt; slate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The canvas size comes from the CSS on the page body. Scale defaults to 2, so a 1360x740 canvas becomes a 2720x1480 PNG that holds up on a retina display.&lt;/p&gt;

&lt;p&gt;Authoring figures as HTML buys three things that a design tool cannot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;They are diffable.&lt;/strong&gt; A figure is a text file in your repo. Regenerating it after a copy change is one command, not forty minutes of nudging boxes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They are consistent by construction.&lt;/strong&gt; Templates consume design tokens and never hard code a colour, so nothing gets hand picked per image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents are good at it.&lt;/strong&gt; A model writes HTML far better than it steers a canvas.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The part I actually care about
&lt;/h2&gt;

&lt;p&gt;Here is the thing that shaped every design decision in this project.&lt;/p&gt;

&lt;p&gt;An agent cannot see its own output. If a render silently produces a blank white PNG, the agent reports success, moves on, and you find out three steps later when the image lands in your README. &lt;strong&gt;A wrong image at exit 0 is the worst outcome this pipeline can produce.&lt;/strong&gt; It is worse than a crash, because a crash is information.&lt;/p&gt;

&lt;p&gt;So the renderer is aggressively paranoid, in two phases you can see in the diagram above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before Chrome launches&lt;/strong&gt;, everything the page needs is resolved rather than left for the browser to fetch. A missing stylesheet is fatal. An unknown element id is fatal, and the error lists the ones that exist. An image is read off disk, format checked and inlined as a data URI. A file that is really a text file with a &lt;code&gt;.png&lt;/code&gt; extension is fatal, naming the path.&lt;/p&gt;

&lt;p&gt;Why bother? Because every one of those failures otherwise produces a page that renders perfectly and screenshots as a flawless success, with an invisible hole where your content should be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After the screenshot&lt;/strong&gt;, the PNG is decoded and inspected. If the luminance spread says nothing but background got painted, it is rejected. Truncated files are rejected. Wrong dimensions are rejected. The bad file is left on disk so you can look at it.&lt;/p&gt;

&lt;p&gt;Every guard exists because something once succeeded quietly and wrongly. Twenty two invariants in the self test suite keep them honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Themes are just tokens
&lt;/h2&gt;

&lt;p&gt;Eight themes ship with it. Templates consume tokens only, so one source file renders in any of them. Same markup, one flag:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwo1dmb02g8mjkhr3lvt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwo1dmb02g8mjkhr3lvt8.png" alt="A deployment blueprint generated with different theme" width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every colour token also ships a component twin, three bare OKLCH numbers, so any transparency of any accent is one expression away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.badge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--a1-raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;12%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--a1-raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;45%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--a1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solid token is built from those same components, so a wash can never drift from the colour it is a wash of. An invariant refuses any theme whose component tokens are not composable, because a broken one paints nothing rather than failing.&lt;/p&gt;

&lt;p&gt;Adding a theme is one CSS file defining the same token set.&lt;/p&gt;

&lt;h2&gt;
  
  
  57 elements you reference, not copy
&lt;/h2&gt;

&lt;p&gt;Figures assemble from a library of parts: browser and phone and terminal frames, databases, servers, queues, routers, a 3D deployment cube, thirty icon glyphs, and the full chart vocabulary. A figure references one instead of carrying a copy of its geometry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;data-part=&lt;/span&gt;&lt;span class="s"&gt;"el-database"&lt;/span&gt; &lt;span class="na"&gt;data-accent=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;transform=&lt;/span&gt;&lt;span class="s"&gt;"translate(70,452)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvd2pekcpbasp92vnilws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvd2pekcpbasp92vnilws.png" alt="The element library rendered in the slate theme" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are chart and BI parts too, but with an important caveat worth repeating loudly: &lt;strong&gt;these are schematics of charts, not charts.&lt;/strong&gt; Every proportion in them is fixed and arbitrary. They exist so a figure can say "a dashboard goes here" the way a cylinder says "a database goes here". If your numbers are the point, plot them with a real charting library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Animated GIFs, with no ffmpeg
&lt;/h2&gt;

&lt;p&gt;This is my favourite corner of the codebase. Sequence diagrams can animate, one step at a time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F565zbp3v9k29f0hohgqg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F565zbp3v9k29f0hohgqg.gif" alt="An animated sequence diagram" width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is no ffmpeg, no encoder binary, no dependency. Chrome renders the frames in parallel, Node's built in zlib decodes the PNGs, a median cut quantizer builds a shared palette with ordered dithering, and a hand rolled GIF89a and LZW encoder assembles the result. Frames after the first store only the changed region as transparent pixel deltas, so tween frames cost almost nothing.&lt;/p&gt;

&lt;p&gt;GIF is a 1989 format. It turns out you really do not need a toolchain for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it deliberately does not do
&lt;/h2&gt;

&lt;p&gt;Being clear about the edges is more useful than overselling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It is not a charting library.&lt;/strong&gt; Give it a dataset and it will still draw a schematic. Use a plotting library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It needs a shell and a local browser.&lt;/strong&gt; That rules out claude.ai chat, the Skills API and most CI images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme fonts come from Google Fonts.&lt;/strong&gt; Offline renders still succeed, but they fall back to system fonts and will not match the previews. Inlining the fonts as data URIs is on the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Give it a go
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add imshaikot/render-visual-skill
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;render-visual-skill@render-visual-skill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then just ask for a diagram.&lt;/p&gt;

&lt;p&gt;The repo is &lt;a href="https://github.com/imshaikot/render-visual-skill" rel="noopener noreferrer"&gt;imshaikot/render-visual-skill&lt;/a&gt;, MIT licensed. Issues and pull requests welcome, and I am especially interested in new themes, since each one is a single CSS file.&lt;/p&gt;

&lt;p&gt;If you build something with it, I would genuinely like to see it.&lt;/p&gt;

</description>
      <category>agentskills</category>
      <category>ai</category>
      <category>productivity</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
