angularaimcptokensclaudegroktailwindcssrich-text-editor

Claude or Grok on a rich text editor: token cost with Ply vs from scratch

Ply — ply-ui.com shows why an AI agent spends far fewer tokens on a rich text editor when it copies the widget in, instead of generating toolbar, selection, sanitizer, and SSR fixes from a blank file.

7 min read Ply team
Simulated recording

Without Ply

Claude writes the editor

session 0:00
0 tok
Input
0
Output
0

Waiting for prompt

With Ply

Claude copies the editor

session 0:00
0 tok
Input
0
Output
0

Waiting for prompt

Same prompt, two reconstructed Claude sessions. From scratch lands around 0 tokens; with Ply around 0. This is a simulation of typical agent turns against the real 576-line rich-text-editor — not a timed lab run.

Ply — ply-ui.com — is a copy-in Angular + Tailwind library. Give Claude Code or Grok in Cursor the same job — add a rich text editor with a toolbar, lists, links, and forms — and the token meter diverges immediately. From scratch the agent writes selection code, hits document is not defined on prerender, and keeps the whole file in context for every retry. With Ply it searches the registry, runs npx ply-ui-cli add rich-text-editor, and wires [(ngModel)]. The recording above is a simulation of those two sessions, not a lab benchmark.

The live widget is on /base-elements/rich-text-editor/. The copied source in this repo is 576 lines across .ts, .html, and .spec.ts.


What the recording is counting

OpenAI’s rule of thumb is that one token is about four characters of English (OpenAI Help). Anthropic bills Claude the same way: every prompt, tool result, and model reply is tokens, and earlier turns stay in the window (Anthropic: token counting). Grok in Cursor is still an LLM in a chat loop — input plus output, accumulated.

That is why a “simple” editor gets expensive without a library. The agent does not pay once for 576 lines. It pays again each turn for the files it already wrote, plus the error, plus the rewrite.

From scratch (reconstructed) With Ply (reconstructed)
Turns 11 4
Input tokens 106,200 6,820
Output tokens 18,400 1,120
Total 124,600 7,940
Session clock 22m 40s 1m 18s
Result Still iterating (lists, links, sanitizer) Editor copied and bound

Toggle Claude / Grok on the recording for the chrome. The token path is the same reconstructed session either way — we did not A/B the two models in a timed harness.


Why the scratch path burns context

A usable Angular editor is not a contenteditable div. Ply’s ply-rich-text-editor already includes:

  • Toolbar: undo/redo, headings, bold/italic/underline/strike, lists, alignment, link, clear
  • ControlValueAccessor so [(ngModel)] and formControlName work
  • selectionchange so button state follows the caret
  • SSR gates so document is not touched during prerender
  • HTML normalization before emit

Angular’s security guide is blunt that innerHTML is a sink. An agent that pastes HTML into the page without a sanitizer is not finished, even if the toolbar paints.

Typical failure loop we reconstructed (the left pane):

  1. Writes a component that does not implement ControlValueAccessorNG8002.
  2. Reads document in ngAfterViewInit → prerender throws.
  3. Bold state does not track the caret → rewrite execCommand helpers.
  4. Spec (or a reviewer) flags untrusted HTML → another file, another turn.

Each miss keeps the previous TypeScript in the prompt. That is the token cliff.


Why the Ply path stays small

Copy-in UI means the editor is files in src/, not a minified bundle in node_modules. The agent can read the template. It does not have to invent ::ng-deep against a vendor class it hallucinated. That architectural argument is the longer copy-in + MCP article. This page is the token-shaped version of it.

The right-hand session:

  1. Same prompt.
  2. search_components("rich text editor") on npx -y ply-ui-mcp (or llms.txt).
  3. npx ply-ui-cli add rich-text-editor — Pro widget, so the CLI uses PLY_LICENSE_KEY. MCP add stays on the free catalog.
  4. One page edit: <ply-rich-text-editor [(ngModel)]="html">.

The 576 lines still exist. They are not generated in the chat. They are copied once, then the model writes a handful of lines to use them.

shadcn/ui describes the same install model: “The idea behind shadcn/ui is to give you ownership and control over the code, by providing a CLI to install components into your project.” (ui.shadcn.com/docs). Ply is that model on Angular with Tailwind CSS.


How to read the numbers

Treat 124,600 vs 7,940 as a worked example, not a guarantee. Your bill depends on the host (Cursor, Claude Code, a Grok sidebar), how much of the repo is already in context, and whether the agent keeps retrying. A shorter prompt on a page that already has Ply initialized will be cheaper than our scratch column. A longer “make it like Notion” prompt will be more expensive than our Ply column.

What does not change:

  • Generating a toolbar, selection model, CVA, and SSR-safe document access from zero is many turns.
  • Copying rich-text-editor is one CLI call plus a bind.
  • Tokens accumulate. Retries are the expensive part.

Same prompt you can paste

Add a rich text editor to this Angular app. I need a formatting toolbar,
headings, bold/italic/underline, lists, links, and it must work with
Angular forms. Prefer an existing Ply component if one exists.

With MCP connected (Getting started — AI agents):

npx ply-ui-cli init --yes
export PLY_LICENSE_KEY=<key>   # rich-text-editor is Pro
npx ply-ui-cli add rich-text-editor

Then point the agent at ply-ui.com/llms.txt.


Try the editor, not just the meter

The reconstructed recording is a teaching device. The component is real:

<ply-rich-text-editor [(ngModel)]="bioHtml" placeholder="Write something..."></ply-rich-text-editor>

Open the rich text editor demo, or start from the free primitives if you want the agent to assemble a page from buttons, inputs, and dialogs instead of a Pro widget.

Frequently asked questions

Same wording as the canonical FAQ.

Usually, yes. With Ply the agent copies a finished component (CLI or MCP) and wires it, instead of generating a toolbar, selection model, sanitizer, and SSR guards from a blank file. Token use still depends on the prompt and the model. A reconstructed Claude/Grok session for the rich text editor is at https://ply-ui.com/learn/ai-agent-tokens-rich-text-editor/ — that is a teaching simulation, not a lab benchmark.

Yes. npx -y ply-ui-mcp is stdio for Cursor, Claude (Code/Desktop), Kimi, VS Code, Windsurf, and other local hosts. ChatGPT and Gemini chat apps use the Streamable HTTP connector at https://mcp.ply-ui.com/mcp (catalog tools) or a local npx -y ply-ui-mcp --http without --read-only so add/init/update can see the project. Pro add uses PLY_LICENSE_KEY on the MCP process. Editors that skip MCP can copy the Cursor rule and snippet pack from https://ply-ui.com/getting-started/#editor-rules.

npx ply-ui-cli init once per project, then npx ply-ui-cli add <name>. Omit the name in a terminal to pick from the catalog (filter, then type to select). --yes and CI need explicit names. Components land in src/app/components/<name>/ by default and are yours.

Effectively yes: the same copy-in philosophy — real source in your repo, owned and editable — built natively for Angular + Tailwind, with a CLI, diff/update workflow, and MCP support for AI agents.

Start with the free tier

All primitives, all 19 form blocks, and 390 icons — no account, no licence key.