skills/diff-all/SKILL.md
Diffs every frame in a Figma file against stored snapshots. Runs structural diff locally (zero API calls), dispatches vision analysis only on changed frames, and computes comment deltas. Produces a tiered report. Use when the user runs /figma-differ:diff-all with a Figma file URL, or says "diff all frames", "what changed in this Figma file", "bulk diff", "check for design changes", or "run a full file diff".
npx skillsauth add tokyo-megacorp/figma-differ diff-allInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Extract fileKey from the Figma URL (https://www.figma.com/design/<fileKey>/...).
Parse flags: --notify (post to Slack after), --top N (default 10, how many detailed entries).
bash scripts/auth.sh status (if it fails, tell the user to run bash scripts/auth.sh set and stop)~/.figma-differ/<fileKey>/index.jsonnode.json under ~/.figma-differ/<fileKey>/)/figma-differ:snapshot-all <url> firstCreate tasks per phase. Use haiku subagents for mechanical steps (fetch, structural diff). Reserve main model for vision analysis and report synthesis.
TaskCreate("Fetch current state", activeForm: "Fetching latest frames from Figma API...")
TaskCreate("Detect structural changes", activeForm: "Comparing node trees against baselines...")
TaskCreate("Detect visual changes", activeForm: "Comparing screenshots via Claude vision...")
TaskCreate("Check comment changes", activeForm: "Comparing comment threads since last snapshot...")
TaskCreate("Generate change report", activeForm: "Ranking changes by severity...")
Task lifecycle:
TaskUpdate(taskId, status: "in_progress")Agent(model: "haiku") for mechanical work (fetch, structural diff, comments). Vision analysis uses the main model (needs image understanding).TaskUpdate(taskId, status: "completed")~/.figma-differ/)Pipe directly to a temp file (do NOT store in shell variable — file trees can be 10-30MB):
TREE_FILE="/tmp/figma-tree-<fileKey>-$$.json"
bash $CLAUDE_PLUGIN_ROOT/scripts/figma-api.sh fetch_file_tree <fileKey> > "$TREE_FILE"
Split into per-frame JSONs in a temp directory using jq. For each frame in the index:
IMPORTANT: Do NOT use jq recursive descent (..) — it hangs on large trees.
jq --arg id "<nodeId>" '
[.document.children[].children[]? | recurse(.children[]?) | select(.id == $id)] | first
' "$TREE_FILE" > "/tmp/figma-current/<nodeId_safe>.json"
For each frame in the index:
~/.figma-differ/<fileKey>/<nodeId_safe>/ directories by name (dirname IS the timestamp — do NOT use ls -t which sorts by filesystem mtime)diff -q /tmp/figma-current/<nodeId_safe>.json ~/.figma-differ/<fileKey>/<nodeId_safe>/<latest_timestamp>/node.jsonThis is instant — bash file comparison, no API calls, no LLM calls. Typically 80-90% of frames are unchanged and get skipped here.
For frames that differ (from step 4):
structural-differ agent with baseline and current pathsLLM cost is proportional to actual changes, not total frames.
For frames where structural diff found changes (severity > "none"):
fetch_batch_images for all changed frame IDs (chunked at 10)vision-analyzer agent with reference and current imagesPipe directly to file (do NOT store in shell variable — 3000+ comments will exceed argument limits):
COMMENT_DIR="$HOME/.figma-differ/<fileKey>/comments"
mkdir -p "$COMMENT_DIR"
bash $CLAUDE_PLUGIN_ROOT/scripts/figma-api.sh fetch_comments <fileKey> > "/tmp/figma-comments-current.json"
Find latest stored comments: sort ~/.figma-differ/<fileKey>/comments/ by filename.
Compute delta:
resolved_at was null in stored but non-null in currentparent_id that exist in current but not in storedGroup by client_meta.node_id to link comments to frames.
Format output with --top N most significant changes:
File Diff Report — <fileName>
<timestamp> vs baseline <baseline_timestamp>
Summary: X/Y frames changed | Z new comments | W resolved
--- Top N by severity ---
1. [CRITICAL] Frame "Login Screen" (2895:40497)
Structural: 3 nodes added, 1 removed, 5 changed
Visual fidelity: 3/5
Comments: 2 new unresolved
Action items:
- Fix heading font-weight: 400 -> 600
- New button component not in previous design
2. [HIGH] Frame "Recovery Flow" (2895:40501)
Structural: 2 nodes changed (text content, fill color)
Visual fidelity: 4/5
...
--- N more frames changed (one-line summaries) ---
- [MEDIUM] "Settings" — 1 property change (fill color)
- [LOW] "Profile Header" — spacing adjustment (4px)
...
--- Comment Activity ---
New unresolved (12):
- [Designer Name] on "Login Screen": "Button needs to be primary variant" (2h ago)
- ...
Resolved (5):
- "Icon alignment issue" on "Recovery Flow" — resolved by Designer Name
- ...
JSON — Save the raw structured output from bulk-diff.js (the JSON that scripts/diff-all.sh produces) to ~/.figma-differ/<fileKey>/latest-diff-all.json. This is the primary data file used by the notify skill.
Enrich the JSON before saving: add a comments key with the comment delta computed in step 7:
{
"total": ...,
"unchanged": ...,
"top": [...],
"rest": [...],
"comments": {
"new": [
{ "id": "comment-id", "author": "Author Name", "text": "comment text", "nodeId": "2895:40497", "createdAt": "..." }
],
"resolved": [
{ "id": "comment-id", "text": "comment text", "resolvedBy": "Author Name", "nodeId": "2895:40501", "resolvedAt": "..." }
]
}
}
Markdown — Also write the human-readable report to ~/.figma-differ/<fileKey>/latest-diff-all.md.
If --notify flag was passed, run the notify workflow.
Otherwise: Run /figma-differ:notify to post this to Slack.
Store the current tree split as new snapshots (per-frame node.json files) and current comments as ~/.figma-differ/<fileKey>/comments/<timestamp>.json. This ensures the next diff-all run only reports NEW changes — prevents scheduled polling from re-reporting the same changes.
Important: Advance the baseline AFTER notify completes. If notify fails, do not advance — the next run will re-report the same changes and retry delivery.
Remove temp files: rm -rf "$TREE_FILE" /tmp/figma-current/ /tmp/figma-comments-current.json
testing
Subscribe to a Figma file for automatic syncing and semantic search. Adds the file to tracked.json, runs initial index + snapshot-all + frame.md generation, and initializes the QMD search collection. Use when the user runs /figma-differ:track or says "track this Figma file", "subscribe to Figma", "watch this design file", or "add to tracked files".
documentation
Refresh snapshots and search index for tracked Figma files. Fetches current state from Figma, generates frame.md documents, and updates the QMD search index. Use when the user runs /figma-differ:sync or says "sync Figma", "refresh snapshots", "update the Figma index", or "re-sync tracked files".
tools
Takes a snapshot of a Figma node — fetches its JSON structure and PNG screenshot and stores both to ~/.figma-differ/ for later diffing. Use when the user runs /figma-differ:snapshot with a Figma URL, or says "snapshot this Figma frame", "save a Figma baseline", or "take a Figma snapshot".
development
Bulk snapshots every frame in a Figma file — fetches all node JSONs, exports PNGs, and stores comments. Uses a single API call for the tree and batched image exports. Use when the user runs /figma-differ:snapshot-all with a Figma file URL, or says "snapshot all frames", "bulk snapshot", "baseline the whole file", or "snapshot everything in this Figma file".