How this command is triggered — by the user, by Claude, or both
Slash command
/workflowy:ui-diffThe summary Claude sees in its command listing — used to decide when to auto-load this command
# UI Diff Deep-Dive: Production vs Local Compare UI components between production workflowy.com and localhost:5173 using Chrome DevTools MCP. ## Goal: Exact Replication **Our goal is pixel-perfect replication of Workflowy, including CSS class names.** Production Workflowy is the source of truth. When in doubt: - Use the same CSS class names as production - Use the same DOM structure as production - Use the same CSS property values as production - Match their CSS variables (--wf-\*, etc.) This is not "inspired by" - this is an exact clone for personal use. ## Prerequisites Ensure bot...
Compare UI components between production workflowy.com and localhost:5173 using Chrome DevTools MCP.
Our goal is pixel-perfect replication of Workflowy, including CSS class names.
Production Workflowy is the source of truth. When in doubt:
This is not "inspired by" - this is an exact clone for personal use.
Ensure both sites are open in Chrome:
http://localhost:5173 (local replica)https://workflowy.com (production)Use AskUserQuestion to let user pick which widget category to analyze:
Before analyzing specific widgets, capture the original CSS assets from production Workflowy. This preserves the original authoring structure rather than just computed values.
Extract all stylesheet URLs using mcp__chrome-devtools__evaluate_script:
() => [...document.querySelectorAll('link[rel="stylesheet"]')].map((l) => l.href);
Extract inline style blocks using mcp__chrome-devtools__evaluate_script:
() => [...document.querySelectorAll('style')].map((s) => s.textContent);
Extract CSS custom properties from :root using mcp__chrome-devtools__evaluate_script:
() => {
const root = document.documentElement;
const styles = getComputedStyle(root);
const props = {};
for (const prop of styles) {
if (prop.startsWith('--')) props[prop] = styles.getPropertyValue(prop);
}
return props;
};
Save external CSS files to .llm/reference/css/ for offline reference:
.llm/reference/css/{filename}.css.llm/reference/css/inline-styles.css.llm/reference/css/custom-properties.jsonFor each widget in the selected category:
Take accessibility snapshot using mcp__chrome-devtools__take_snapshot
Take screenshot using mcp__chrome-devtools__take_screenshot
Extract raw HTML using mcp__chrome-devtools__evaluate_script:
(el) => el.outerHTML;
Extract applied CSS rules using mcp__chrome-devtools__evaluate_script:
(el) => {
const sheets = [...document.styleSheets];
const rules = [];
sheets.forEach((sheet) => {
try {
[...sheet.cssRules].forEach((rule) => {
if (rule.selectorText && el.matches(rule.selectorText)) {
rules.push({selector: rule.selectorText, css: rule.cssText});
}
});
} catch (e) {}
});
return rules;
};
Extract computed styles using mcp__chrome-devtools__evaluate_script:
(el) => {
const s = getComputedStyle(el);
return {
// Box model
width: s.width,
height: s.height,
padding: s.padding,
margin: s.margin,
// Typography
fontSize: s.fontSize,
fontWeight: s.fontWeight,
lineHeight: s.lineHeight,
color: s.color,
// Layout
display: s.display,
position: s.position,
top: s.top,
left: s.left,
// Visual
backgroundColor: s.backgroundColor,
opacity: s.opacity,
borderRadius: s.borderRadius,
};
};
Compare and document:
After analyzing all widgets in the category:
Use the markdown-tasks skill to add findings as tasks to .llm/todo.md.
For each mismatch found, create a task like:
- [ ] Fix {widget} class name: rename `.outline-node-content` → `.content`
- [ ] Fix {widget} padding: change `5px 4px 5px 0` → `4px 10px 0 0` in styles.css
- [ ] Fix {widget} DOM structure: wrap text in `.innerContentContainer`
Tasks should be:
After adding tasks, summarize what was found and how many tasks were created.
// Extract everything about a widget
(el) => ({
tagName: el.tagName,
className: el.className,
id: el.id,
attributes: [...el.attributes].map((a) => ({name: a.name, value: a.value})),
outerHTML: el.outerHTML,
computedStyle: (() => {
const s = getComputedStyle(el);
return {
width: s.width,
height: s.height,
padding: s.padding,
margin: s.margin,
fontSize: s.fontSize,
lineHeight: s.lineHeight,
display: s.display,
position: s.position,
};
})(),
});
packages/web/src/client/styles.css - Main stylespackages/web/src/client/components/outline-node.tsx - Node componentspackages/web/src/client/components/top-bar.tsx - Headerpackages/web/src/client/components/breadcrumbs.tsx - Navigationselect_page to switch between tabsnpx claudepluginhub motlin/workflowy-cli --plugin workflowy