validate-screenshots
Automates the review of screenshots for technical documentation against predefined visual standards.
Install
mkdir -p .claude/skills/validate-screenshots && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10660" && unzip -o skill.zip -d .claude/skills/validate-screenshots && rm skill.zipInstalls to .claude/skills/validate-screenshots
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Validates PNG screenshots in an OutSystems docs article against the team's visual rules (highlight components, shadow, cursor, naming, cropping). Returns a short issues-only summary so the content developer knows whether the images are ready for design review. Use when a content developer wants to check their screenshots before merging, or asks to "review screenshots", "check my screenshots", "validate screenshots", "screenshot review". Trigger phrases: "validate screenshots", "review screenshots", "check my screenshots", "are these screenshots good", "screenshot review".Key capabilities
- →Review screenshots
- →Validate visual rules
- →Check metadata
- →Detect duplicates
How it works
Validates PNG screenshots against a calibrated rubric using automated checkers and vision.
Inputs & outputs
When to use validate-screenshots
- →Review screenshots
- →Check visual rules
- →Validate docs imagery
- →Screenshot review
About this skill
Validate screenshots
Runs a design-system review on PNG screenshots a content developer added to an OutSystems docs article, so they can self-check before asking for manual design review.
The rubric lives in visual-rules-screenshots.md next to this file — it is
produced by running scripts/calibrate.py against a reference set of approved
screenshots. If that file is still a placeholder, stop and tell the user to run
calibration first (see the Calibration section below).
Setup
Read visual-rules-screenshots.md from the same directory as this SKILL.md.
If it still contains the placeholder marker (<!-- NOT CALIBRATED -->), stop
and print:
"No screenshot rubric yet. Run
scripts/calibrate.pyonce with a set of approved screenshots to generatevisual-rules-screenshots.md, then try again."
Step 1: Resolve targets
Call the target collector with whatever the user passed (default to empty):
python3 -B <skill-dir>/scripts/collect_targets.py "$ARGUMENTS"
It prints a JSON array to stdout. Each entry has:
image_path— absolute path to the PNGarticle_path— the markdown that references it, ornullshared_with— only present on a single-image invocation when the calling workflow already knows the image is referenced by more than one article changed in this same pull request; a list of those articles' absolute paths. Mutually exclusive witharticle_pathbeing set — see "Choosing the summary title" in Step 3.
If the array is empty, stop with:
"No screenshots to validate. Pass a markdown file, a PNG path, or run without arguments on a branch that has image changes vs. master."
Duplicate detection
After collecting targets, group entries by their sha256 field. If two or
more entries share a hash, the files are byte-for-byte identical and only
one copy should exist. Mark every duplicate with a ❌ finding in the final
summary:
"Byte-identical duplicate of
<other image name>. Keep one and delete the rest."
Empty sha256 values (file unreadable) are not grouped.
Run this over every entry, including ones marked "cached": true.
Whether an image duplicates another depends on the whole set, not on that
image's own content, so a cached image can become a duplicate when a new copy
is added and stop being one when the copy is deleted. This grouping is cheap
and needs no vision, so it is never skipped. Note sha256 is used here and
nowhere else; the cache keys on blob_sha instead.
Step 2: Validate each target
Cached entries first. If an entry has "cached": true, this exact file
content already passed this rubric on an earlier run. Skip the numbered steps
below for it entirely — no Read into vision, no checker scripts — and reuse
its cached_findings array verbatim as that image's findings (an empty array
means it passed clean). It still counts toward N in Step 3, and toward M
when cached_findings is non-empty. Do not re-word, re-order, or re-judge a
cached finding: it was produced by this same rubric and must read identically
so the report stays stable across runs.
cache_reason and cache_detail on each entry say why it was or wasn't
cached; they are for the log, not for the report.
For every entry that is not cached:
-
Read the image with the Read tool so it goes into vision.
-
Run the deterministic checkers. They are authoritative for the rules they cover — do not second-guess them from vision.
python3 -B <skill-dir>/scripts/check_metadata.py "<image_path>" python3 -B <skill-dir>/scripts/has_shadow.py "<image_path>" python3 -B <skill-dir>/scripts/check_red.py "<image_path>"check_metadata.pyprints JSON covering rule 1 (PNG format), rule 2 (filename regex + surface suffix, including double-suffix detection), and rule 10 (width ≤ 1200 px). Parse the JSON and use each verdict directly.has_shadow.pyprints one ofshadow: true/shadow: wrong/shadow: false/shadow: inconclusive/shadow: unknownfor rule 6. Map them to severity as follows:truepasses.wrongis ❌ — output exactly this text (do not paraphrase): "Shadow doesn't match the TK-shadow effect available in the TK design library — apply it from the Effects menu in Figma (rule 6)".falseis ❌ for large-surface captures and ⚠️ otherwise — never a clean pass, so the reviewer always sees it and can dismiss when it's genuinely a self-bounded close crop. Output exactly this text (do not paraphrase): "Missing TK-shadow effect available in the TK design library — apply it from the Effects menu in Figma (rule 6)".inconclusiveis ⚠️ — the alpha channel is present but the detector couldn't reach opaque content on the sampled edges (e.g. content far from the borders, transparent mid-edges). Output exactly this text (do not paraphrase): "Shadow check inconclusive — designer should verify the TK-shadow effect available in the TK design library (Effects menu in Figma) is applied (rule 6)". Do not restate it as "missing shadow" — the script didn't say that.unknownmeans the image has no alpha channel at all (typically a JPG saved as.png, which rule 1 already fails); don't emit a separate shadow finding in that case. Do not suppress afalseverdict based on your own close-crop judgment — surface it as ⚠️ at minimum. Refer to rule 6 in the rubric for the full definitions.check_red.pyprints one ofred: ok #RRGGBB/red: wrong #RRGGBB (token #F22800)/red: nonefor the color half of rule 3. Map it as:okpasses;nonepasses (the image has no red highlight, so there's nothing to color-check);wrongis ⚠️ — phrase as "Highlight red is #RRGGBB, not the design-system token #F22800 — re-snap from the Figma library", quoting the actual hex from the script so the user can confirm. Vision can't reliably distinguish similar reds (#F22800 vs #CC2200 vs #BB1F00), so do not second-guess the script.
-
Use vision only for the rules the scripts don't cover: rule 2's suffix-vs-content mismatch (filename says
-ssbut the image shows ODC Studio), rule 3's placement (whether a highlight is present and on the right element — the color is scripted; checkvisual-rules-screenshots.mdrule 3's "Native selection state" case first — if the product's own selection highlight already marks the focal element but no red rectangle was added, that's a ⚠️ with the quoted verdict wording, not a ❌; only fail ❌ when there's neither a red rectangle nor a native selection state), rule 4 (numbered callouts), rule 5 (arrows), rule 7 (PII), rule 8 (internal environment URLs).For
-ss/-odcsfiles showing an entity or data-model layout (boxes connected by lines), check againstvisual-rules-screenshots.mdrule 2's entity/data-model carve-out before concluding the suffix is wrong. A Data-tab capture cropped tight with no toolbar chrome is not by itself a sign of a misfiled-diagdiagram — don't fall back on the genuine-diagram checklist below as the only reference point for that judgment.For files ending in
-diag: use vision to determine whether the content is a genuine diagram or a UI screenshot.A genuine diagram has all of the following:
- No product UI chrome (no IDE toolbars, portal navigation, or browser address bar)
- A conceptual layout: flow chart, sequence diagram, hierarchy tree, architecture box, icon grid, or swimlane diagram
- OutSystems branded orange/red iconography representing concepts
- Connecting elements: arrows, dashed lines, or swimlanes
- A white or light-gray background with a rounded-rectangle shadow border
- Descriptive text labels naming concepts or roles, not UI controls
Excluded: entity or data-model diagrams captured directly from Service Studio's or ODC Studio's Data tab, even when cropped tight with no visible toolbar chrome. These are native tool renderings, not standalone Figma diagrams — refer to
visual-rules-screenshots.mdrule 2's entity/data-model carve-out for the native iconography and connector traits that identify them.A UI screenshot shows product interface chrome with interactive elements (panels, toolbars, dropdowns, form fields, menus) from ODC Studio, ODC Portal, Service Studio, or similar tools.
- If the content is a genuine diagram → suffix is correct; no naming finding.
- If the content is a UI screenshot → emit ❌ Rule 2: "Image looks like
a UI screenshot but uses the
-diagsuffix — rename with the correct surface suffix (e.g.-ss,-odcs)."
-
Collect only failures and warnings — passing rules are not reported.
Keep per-image notes internal until every image is processed. Do not stream partial reports.
Extract the Figma link (once per article)
If any entry has a non-null article_path, open that markdown file once and
grep its YAML frontmatter for a figma: key (the value is a figma.com URL).
Remember the value — the report header will surface it so the content
developer can jump straight to Figma to fix things. If the frontmatter has no
figma: field, or the value is empty, skip the link entirely (don't print an
empty Figma: line).
When multiple articles reference different screenshots (branch-diff mode), collect the unique Figma URLs per article and emit them grouped under each article in the header. In the common single-article case, one line is enough.
Step 3: Emit the summary
Verdict block (always, before anything else)
Print one line recording the outcome for every target in this invocation —
cached and freshly validated alike — before any other Step 3 output, and
before the <!-- REPORT BEGIN --> sentinel the calling workflow expects:
<!-- VERDICTS {"src/foo/images/a-ss.png":
---
*Content truncated.*
When not to use it
- →Non-PNG images
- →Second-guessing scripts
Prerequisites
Limitations
- →Requires calibration
- →Limited to PNG format
How it compares
Provides automated, rubric-based visual validation instead of manual design review.
Compared to similar skills
validate-screenshots side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| validate-screenshots (this skill) | 0 | 3mo | Review | Beginner |
| draw-io | 41 | 8mo | Review | Intermediate |
| ui-design-system | 29 | 9mo | Review | Beginner |
| design-md | 27 | 5mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by OutSystems
View all by OutSystems →You might also like
draw-io
davila7
draw.io diagram creation, editing, and review. Use for .drawio XML editing, PNG conversion, layout adjustment, and AWS icon usage.
ui-design-system
davila7
UI design system toolkit for Senior UI Designer including design token generation, component documentation, responsive design calculations, and developer handoff tools. Use for creating design systems, maintaining visual consistency, and facilitating design-dev collaboration.
design-md
sickn33
Analyze Stitch projects and synthesize a semantic design system into DESIGN.md files
state-machine
WellApp-ai
Document UI component states (current vs expected) with transitions
brief
educlopez
Write or update the project's durable design brief at .ui-craft/brief.md. Invoke when the user asks for brief on their UI, or mentions 'brief' alongside design / UI / frontend work.
positron-abstract-svg
posit-dev
>