agentsclimarketplace

Live ui generation

Skill tamal-thetaonelab/frontloop/skills/live-ui-generation

Enables live UI generation by click-inspecting DOM elements or capturing screenshots, then applying code fixes with a generating animation. Use for "inspect element", "live UI generation", "live gen", "fix this element", "update this component", "change this UI", "edit this part of the page", "make this look different", or when visually selecting DOM elements for modification. Also handles teardown — use for "stop frontloop", "remove frontloop", "uninstall live-ui-generation", or "stop the servers". Does not apply to general code generation without element inspection.From its SKILL.md

Install
npx -y skills add tamal-thetaonelab/frontloop --skill live-ui-generation

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

21.8 KB, as published. Nobody here has run it

Live UI Generation

Overview

Closes the loop between browser and Claude via three modes:

  • Element inspect: Hover ⋞ FAB → transforms to ✛ Inspect → click element → describe fix. Orange shimmer appears, and the TASK payload arrives in the shell.
  • Screenshot capture: Hover ⋞ FAB → click [] Screenshot → drag to select region → describe fix. TASK payload includes screenshotPath.
  • Undo: Hover ⋞ FAB → click ↩ Undo (red when history exists). Sends UNDO task; Claude reverts the last change and reloads.
Browser ──WS──▶ ws-task-server (stdout) ──▶ Claude reads TASK, applies change
  ▲                                                        │
  └──────────── HTTP POST /complete/<id> ◀────────────────┘

Browser ──WS──▶ ws-task-server (stdout) ──▶ Claude reads UNDO, reverts change
  (fire-and-forget — no COMPLETE response)

FAB: Fixed bottom-right. Hover transforms the FAB from ⋞ to ✛ (Inspect), reveals two dial items: ↩ Undo (grey/red) and [] Screenshot (indigo), plus an "Inspect" label next to the FAB. Hides entirely while any operation is active; Escape restores. Only active in dev mode — guarded by window.__FRONTLOOP_ENABLED__ set from the framework's env variable. Clicking the FAB itself starts inspect mode — the click is never wasted.

Console error capture: Both the inspect and screenshot prompt panels include a "Send console errors" checkbox. When checked, captured console.error calls are included in the TASK payload. A live [N errors] counter appears next to the checkbox.

Undo stack: Task IDs stored in sessionStorage (__frontloop_undo_stack__). Survives page reloads. Button turns red when non-empty, grey when empty.

Architecture

ComponentLocationRole
WS + HTTP server<repo-root>/ws-task-server.<server-ext>WS 7332, HTTP completion + reload + screenshot on 7333
Client bundle<frontend>/public/frontloop-bundle.js (copied from reference/live-ui-bundle.js)Self-contained ESM bundle: FAB, WebSocket, console error capture. Guards on window.__FRONTLOOP_ENABLED__ — no-op in production.
  • <repo-root> — git rev-parse --show-toplevel
  • <frontend> — dir with src/ + package.json with a dev server script
  • <server-ext> — .js if package.json has no "type": "module", otherwise .cjs (the server uses CommonJS require())

Monitoring

The Monitor tool spawns a persistent background process. ws-task-server.<server-ext> emits TASK: {...} lines to stdout — each line is a real-time notification. Use Monitor, not Bash; Bash is ephemeral and cannot host a persistent WebSocket server reliably.

Sandbox note: If Claude Code is running inside its network sandbox, Monitor inherits the same restrictions and the server will fail to bind with EPERM: operation not permitted. See Step 3 for the sandbox-safe fallback.

Setup

Claude handles steps 1–5. Step 6 (dev server) must be started by the user.

Step 1 — Resolve repo paths

Identify <repo-root> and <frontend> using the rules above.

Step 2 — ws-task-server

Copy reference/ws-task-server.js verbatim to <repo-root>/ws-task-server.<server-ext>. Use bash to copy — do not reconstruct from memory. Check package.json for "type": "module" first to resolve <server-ext> (.cjs if present, .js otherwise).

Check whether ws is available before starting the server:

ls <frontend>/node_modules/ws 2>/dev/null && echo "ws found" || echo "ws missing"

If missing, install it as a dev dependency in the frontend:

cd <frontend> && npm install --save-dev ws

Step 3 — Start server with Monitor

If the server is already running (lsof -i :7332 | grep LISTEN shows a process), skip launching a new server and go straight to starting the Monitor — do not wait for the user to ask. Always start the Monitor before handing back to the user.

Normal path (no sandbox):

# Via Monitor — server stdout becomes real-time TASK notifications
NODE_PATH=<frontend>/node_modules node <repo-root>/ws-task-server.<server-ext>

Sandbox path — if the Monitor attempt fails with EPERM: operation not permitted on port 7332, the Claude Code sandbox is blocking listen(). Use Bash with dangerouslyDisableSandbox: true instead:

# 1. Start server detached, log to file
NODE_PATH=<frontend>/node_modules node <repo-root>/ws-task-server.<server-ext> \
  > /tmp/ws-task-server.log 2>&1 &

# 2. Then Monitor the log file for TASK events
tail -f /tmp/ws-task-server.log | grep --line-buffered -E "TASK:|UNDO:|ERROR|Error|WS on|HTTP on"

The Bash call needs dangerouslyDisableSandbox: true (Claude Code will prompt for permission). The Monitor on the log file does not need sandbox disabled — it is just reading a file.

Verify either path: lsof -i :7332 | grep LISTEN && lsof -i :7333 | grep LISTEN. Expect ws-task-server: WS on 7332, HTTP on 7333.

Step 4 — Copy bundle to public/

Locate the bundle relative to this SKILL.md:

find ~/.claude -path '*/live-ui-generation/reference/live-ui-bundle.js' 2>/dev/null | head -1

Copy it to the project's public folder:

cp <skill-bundle-path> <frontend>/public/frontloop-bundle.js

For CRA the public folder is <frontend>/public/. For Vite/Vue/Svelte/Angular/vanilla it is also public/ at the frontend root. Verify the file landed at a path that will be served as /frontloop-bundle.js by the dev server.

Step 5 — Inject into HTML entry point

Use the exact inject command from reference/wiring.md for the detected framework. Do not add only the bundle <script> tag — the guard script (window.__FRONTLOOP_ENABLED__) is mandatory and must be injected in the same operation. The bundle is a no-op without it.

Both tags are plain <script> — no type="module" on either. Vite extracts inline type="module" scripts into proxy modules that fail to load; IIFE bundles don't need module semantics. The guard uses a runtime hostname check that works identically across all frameworks:

<script>window.__FRONTLOOP_ENABLED__ = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';</script>
<script src="/frontloop-bundle.js"></script>

Framework → HTML file:

FrameworkHTML entry point
Vite (React / Vue / Svelte)<frontend>/index.html
CRA<frontend>/public/index.html
Angular<frontend>/src/index.html
Next.js App Routersrc/app/layout.tsx (source file — see wiring.md)
Next.js Pages Routersrc/pages/_document.tsx (source file — see wiring.md)
Vanilla<frontend>/index.html

After injecting, verify both lines landed:

grep '__FRONTLOOP_ENABLED__' <html-entry-point> && grep 'frontloop-bundle' <html-entry-point> && echo "both present" || echo "MISSING — check injection"

Step 5.5 — Update .gitignore

Append public/frontloop-bundle.js to <frontend>/.gitignore (or <repo-root>/.gitignore if no frontend-level one):

grep -q 'frontloop-bundle' <frontend>/.gitignore 2>/dev/null || \
  echo 'public/frontloop-bundle.js' >> <frontend>/.gitignore

Also append .rewind/:

grep -q '\.rewind/' <frontend>/.gitignore 2>/dev/null || \
  echo '.rewind/' >> <frontend>/.gitignore

Step 6 — User starts dev server

Claude must NOT start the dev server. Instruct the user to start their dev server.


Usage Flow

Phase A — Element inspect

  1. User hovers ⋞ FAB → transforms to ✛ Inspect, two dial items (Undo, Screenshot) slide out to the left
  2. User clicks ✛ FAB (or Inspect label) → FAB hides, crosshair cursor, elements highlight orange on hover
  3. User clicks element → highlight pinned, prompt panel appears (bottom-right)
  4. User describes fix, optionally checks "Send console errors". Two radios appear: Minimal (default, messages only) and Detailed (full stack traces). A live [N errors] counter shows how many errors are captured.
  5. User presses Enter / clicks "Send Fix Task" — or Escape to cancel
  6. Orange shimmer over element, browser sends TASK via WebSocket with consoleErrors payload if enabled

Phase A2 — Screenshot capture

  1. User hovers ⋞ FAB → clicks [] Screenshot → FAB hides, crosshair cursor
  2. User drags → dashed indigo selection rectangle
  3. User releases → best enclosing container found, screenshot captured as PNG
  4. Panel opens with thumbnail preview, selector, textarea, and same "Send console errors" checkbox + radios
  5. User sends → PNG saved to /tmp/liveui-screenshot-<id>.png. TASK dispatched with screenshotPath and optional consoleErrors
  6. Indigo shimmer over region

Phase A3 — Undo

  1. User hovers ⋞ FAB → clicks ↩ Undo (only active when stack is non-empty)
  2. Browser pops last task ID, sends UNDO: {"id":"<new>","type":"undo","targetTaskId":"<last>"} via WebSocket
  3. Monitor notifies Claude with type: "undo" task
  4. Claude reverts the code change → sends POST /reload

Phase B — TASK arrives

Check type field:

  • "dom-fix" → Phase C
  • "undo" → Phase D (targetTaskId identifies the fix to revert)

If screenshotPath present, Read the image file before planning.

If consoleErrors present (full payload in stderr, slim summary in stdout), review the errors before applying a fix — they may explain the problem the user is reporting (e.g. React deprecation warnings causing blank UI areas). The consoleErrors field has:

  • mode: "minimal" (messages only) or "detailed" (full stack traces)
  • errors: array of { message, stack, timestamp } objects (full errors only in stderr)
  • Slim stdout summary: count (number of errors)

Phase C — Respond and complete

Always send POST /complete/<taskId> at the end of every dom-fix task — even if the prompt was a question, a clarification, or required no code change. The shimmer stays on screen until completion is received; leaving it unsent strands the UI.

  1. Identify the source file from payload: use element.sourceLocation (exact file + line) when present — it's the most reliable signal. Fall back to element.componentHierarchy for React components, page + pageTitle for route components, or container.title for card identity.
  2. If a code change is needed: find and edit the source file.
  3. If a code change was made — run: npx tsc --noEmit 2>&1 | head -40 — zero new errors required. Important: tsc does not catch JSX syntax errors (missing > etc.) — those surface as bundler errors. So run build to identify those.
  4. curl -s -X POST http://localhost:7333/complete/<taskId> — always, regardless of whether code changed.
  5. If a code change was made and HMR seems not working: curl -s -X POST http://localhost:7333/reload

Phase D — Undo

Undo is session-aware: only revert changes made in the current session.

  1. If the change was made this session: revert that edit, run type check, POST /reload
  2. If unknown (prior session): inspect git diff, tell user which file was changed, ask which to revert

No POST /complete for undo — fire-and-forget.

Timing

  • Target: TASK → change → completion in under 60s for simple changes
  • Shimmer auto-clears after 180s if no completion received

Payload Schema

dom-fix

FieldTypeReqDescription
idstringyes8-char alphanumeric task ID
typestringyes"dom-fix"
promptstringyesFree-text fix description
element.selectorstringyesCSS selector
element.tagstringyesLowercase tag name
element.htmlstringyesouterHTML (truncated to 2000 chars)
element.textstringyestextContent (trimmed to 500 chars)
element.stylesobjectyesComputed style properties
element.componentHierarchystringnoReact fiber chain e.g. "th (CurrentTabPane > Table)". null on non-React.
element.sourceLocationstringnoSource file + line of the clicked element, e.g. "components/layout/ActivitySidebar.tsx:30". Path relative to src/. null when not available (see edge cases). Present in slim stdout when non-null.
element.columnIndexnumberno0-based column index when <th> clicked
container.*variednoCard context: selector, tag, html, text, title, value, description, dataKeys
pageTitlestringyesdocument.title
pagestringyeswindow.location.href
screenshotPathstringnoAbsolute path to saved PNG. Use Read to view.
consoleErrorsobjectnoPresent when user checked "Send console errors". Contains mode: "minimal" — messages only, or "detailed" — full stack traces. errors: array of {message, stack, timestamp}. Slimmed in stdout to {mode, count}; full errors in stderr.

sourceLocation source by React version:

  • React 19: always populated — React captures fiber._debugStack (an Error) natively at fiber creation; Vite dev URLs in the stack already contain the original .tsx path.
  • React 16–18 + @vitejs/plugin-react or CRA: populated via fiber._debugSource (set by Babel's @babel/plugin-transform-react-jsx-development).
  • React 16–18 + esbuild/SWC only: null — no source injection in the JSX transform.
  • Non-React (Angular, Vue, Svelte): always null.

undo

FieldTypeReqDescription
idstringyes8-char alphanumeric ID
typestringyes"undo"
targetTaskIdstringyesid of the dom-fix task being undone

Teardown

Run this when the user asks to stop, uninstall, or remove Frontloop from their project.

Detect install version first

ls <frontend>/src/mocks/dom-inspector.ts 2>/dev/null && echo "legacy" || echo "current"
  • legacy (v0.1.0–0.3.0): TS source files in src/mocks/ + provider wiring. Use reference/teardown-legacy.md instead of the steps below.
  • current (v0.4.0+): bundle in public/ + HTML script tag injection. Continue with steps below.

Step T1 — Kill the running servers

lsof -ti :7332,:7333 | xargs kill 2>/dev/null; echo "servers stopped"

Step T2 — Remove the server file and log

rm -f <repo-root>/ws-task-server.js <repo-root>/ws-task-server.cjs
rm -f /tmp/ws-task-server.log

Step T3 — Remove the bundle

rm -f <frontend>/public/frontloop-bundle.js

Step T4 — Remove the script tag injection

Three things were injected — the comment, the guard script, and the bundle script. All three must go.

For Vite (<frontend>/index.html), CRA (<frontend>/public/index.html), Angular (<frontend>/src/index.html), and Vanilla (<frontend>/index.html), run the appropriate command:

# Vite
sed -i '' '/frontloop dev guard/d; /frontloop-bundle/d; /__FRONTLOOP_ENABLED__/d' <frontend>/index.html

# CRA
sed -i '' '/frontloop dev guard/d; /frontloop-bundle/d; /__FRONTLOOP_ENABLED__/d' <frontend>/public/index.html

# Angular
sed -i '' '/frontloop dev guard/d; /frontloop-bundle/d; /__FRONTLOOP_ENABLED__/d' <frontend>/src/index.html

For Angular, also remove the { "glob": "**/*", "input": "public", "output": "/" } asset entry from angular.json (build and test targets) before running the sed command above.

For Next.js, remove the entire conditional <Script> block from layout.tsx / _document.tsx — see reference/wiring.md for the exact block that was added.

Verify nothing remains:

grep -r '__FRONTLOOP_ENABLED__\|frontloop-bundle' <frontend>/index.html <frontend>/public/index.html <frontend>/src/index.html 2>/dev/null && echo "still present" || echo "clean"

Step T5 — Clean up .gitignore

Remove the lines added during setup:

public/frontloop-bundle.js
.rewind/

Step T6 — Confirm

lsof -i :7332 | grep LISTEN || echo "7332 clear"
lsof -i :7333 | grep LISTEN || echo "7333 clear"
ls <repo-root>/ws-task-server.js <repo-root>/ws-task-server.cjs 2>/dev/null && echo "server file still present — recheck T2" || echo "server file clean"
ls <frontend>/public/frontloop-bundle.js 2>/dev/null && echo "bundle still present — recheck T3" || echo "bundle clean"

Tell the user: Frontloop has been removed. Their source files are untouched — all edits made by Frontloop remain in place and in git history.


Edge Cases

SituationAction
TypeScript errors in modified filesFix before completion. If fix requires infra changes, tell user + still send completion
Concurrent tasksComplete task 1 fully before starting task 2
Server not running (lsof -i :7332 empty)Restart via Monitor (Step 3). Shimmer auto-removes after 180s
EPERM: operation not permitted on port 7332/7333Claude Code sandbox is blocking listen(). Start via Bash with dangerouslyDisableSandbox: true + redirect stdout to /tmp/ws-task-server.log, then Monitor the log file (see Step 3 sandbox path)
Completion returns 404WS connection already closed (tab nav/timeout). Shimmer already gone — no action needed
Screenshot upload fails (no screenshotPath)CORS issue — server must set Access-Control-Allow-Origin: * and handle OPTIONS. Reference file handles this.
element.sourceLocation is nullExpected when: React 18 with esbuild-only JSX (no Babel), production builds, or non-React frameworks (Angular/Vue). Gracefully omitted from slim stdout — fall back to componentHierarchy.
FAB doesn't appearCheck window.__FRONTLOOP_ENABLED__ in browser console — must be true. Verify the guard script is injected before the bundle script.
FAB appears in productionGuard expression evaluated to true in prod. Verify the framework env var (e.g. import.meta.env.DEV should be false in Vite prod builds).
Failed to load module script: … MIME type of "text/html"Either the bundle file is missing from public/ (dev server returned its SPA fallback), or a type="module" guard script was used and Vite extracted it into a proxy module that failed to load. Fix: (1) verify <frontend>/public/frontloop-bundle.js exists; (2) ensure neither the guard nor the bundle script tag has type="module".
Guard or bundle script tag has type="module"Remove it from both tags. Vite extracts inline type="module" scripts into proxy modules (index.html?html-proxy&index=N.js) — if that proxy fails, window.__FRONTLOOP_ENABLED__ is never set and the bundle is a no-op. IIFE bundles don't need module semantics.
window.__FRONTLOOP_ENABLED__ is false in devHostname check failed — dev server is not on localhost or 127.0.0.1 (e.g. remote dev box, custom domain). Open browser console and check window.location.hostname. If needed, manually set window.__FRONTLOOP_ENABLED__ = true in the guard script for that hostname.
Bundle loads but FAB doesn't appearCheck window.__FRONTLOOP_ENABLED__ in the browser console — must be true. Verify the guard script is present and comes before the bundle script.
value.replace is not a functioncssEscape receives a non-string value. Guard with typeof value !== "string"
HMR doesn't reflect changePOST /reload forces full page refresh
Duplicate FAB in DOMBundle loaded twice — check for duplicate script tags in HTML
CSS :hover dial too wideUse JS mouseenter/mouseleave (in reference file). CSS :hover on flex container includes invisible children in hit area
for...of over NodeList failsUse .forEach() — --downlevelIteration may not be enabled
Undo button stays grey after reloadsaveUndoStack() missing after a push(), or updateUndoBtnState() not called
UNDO task for unknown targetTaskIdPrior session — use git diff to identify recent edits and offer to revert

Common Mistakes

MistakeFix
Wrong taskId in curlCopy id verbatim from TASK JSON — 8 alphanumeric chars
Skipping type checkAlways run npx tsc --noEmit before POST /complete
Starting dev server yourselfNever — instruct user to run it
Server MODULE_NOT_FOUNDNODE_PATH must point to <frontend>/node_modules, not repo root
EPERM when starting via MonitorSandbox blocks port binding. Use Bash + dangerouslyDisableSandbox: true + log file + Monitor log (Step 3 sandbox path)
Sending POST /complete for undoUndo is fire-and-forget — only send POST /reload
Not sending POST /complete after a question/clarificationCompletion is always required for dom-fix tasks — even when no code changed. Omitting it leaves the shimmer on screen indefinitely.
type="module" on guard or bundle scriptRemove it — Vite extracts inline module scripts into proxy modules that fail to load; IIFE bundles don't need module semantics
Guard script after bundle scriptwindow.__FRONTLOOP_ENABLED__ must be set before the bundle loads — guard script must come first
Injecting bundle into src/ filesOnly patch the HTML entry point — no TypeScript/JSX source files (except Next.js layout)

Keep looking

Skills are one crate of 628,971. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.