Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Visual quality assurance: analyze game screenshots for defects, compare against reference, check motion in frame sequences. Supports runtime-native inspection plus Gemini or OpenAI API-backed VQA.
.claude/skills/randallliuxin-visual-qa/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 565% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 137% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 119% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 108% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 29% | 0% |
$ARGUMENTS
CRITICAL: Find acceptance-blocking problems. Do not rationalize defects that block the caller-provided Task Context.
CRITICAL: When Task Context is provided, use its Verify: criteria as the gate. Treat the reference image as visual intent, not as a pixel-perfect or style-matching gate. Do not fail a check for pure reference/style mismatch (palette, capitalization, wording, roundedness, spacing, polish) unless it breaks the Verify: criteria, blocks operation, destabilizes layout, or makes the visible state logically false.
If arguments include --log <path>, set VQA_LOG to that path and remove those tokens before mode detection.
Reject unsupported argv shapes such as --screenshot <file> --requirements "...".
Pick the mode from caller args by matching the first row whose precondition holds. If no row matches, STOP and tell the caller their args are malformed.
| Mode | Precondition | Required argv shape | |---|---|---| | Static | references/<ref>.png path AND exactly 1 screenshot path | Check references/<ref>.png against <screenshot.png> - Goal: ... Requirements: ... Verify: ... | | Dynamic | references/<ref>.png path AND 2 or more frame paths | Check references/<ref>.png against <frame_glob> - Goal: ... Requirements: ... Verify: ... | | Question | No references/ path; caller asks a question about screenshots | --question "..." <screenshot.png> [...] |
If a reference path appears in the args but the file does not exist on disk, STOP. Return verdict: error with reason: "reference file missing: <path>".
Screenshot paths for Static/Dynamic mode may come from e2e/screenshots/, reports/fixgap-visual/, or reports/verifier-temp/.
Each call takes one scene's reference plus that scene's screenshot or frame paths. Reject a single stitched, montage, or contact-sheet image supplied in place of per-scene paths.
Read .godotmaker/config.yaml for model selection:
vqa_model: primary VQA backend. Supported values are native, codex, gemini:<model>, and openai:<model>.vqa_fallback_model: fallback when the primary backend is unavailable. Supported values are native, codex, and none.If .godotmaker/config.yaml is missing, vqa_model is missing, or vqa_model is empty, STOP with verdict: error.
Runtime-native VQA means direct image inspection by the selected runtime provider. native uses the active agent runtime. codex uses Codex image inspection, including from a Claude Code orchestration when Codex is available. API-backed VQA runs ${CLAUDE_SKILL_DIR}/scripts/visual_qa.py with --model <vqa_model>.
Do not silently switch providers except for the explicit vqa_fallback_model path.
Use this path when vqa_model is native or codex, or when an API-backed model fails and vqa_fallback_model is native or codex.
scripts/static_prompt.mdscripts/dynamic_prompt.mdscripts/question_prompt.mdscripts/criteria.md.image-reading path.
code.
For native, use the active agent runtime's image inspection. For codex, use Codex image inspection.
Use this path when vqa_model is gemini:<model> or openai:<model>.
Parse the arguments to construct the command. The script is at ${CLAUDE_SKILL_DIR}/scripts/visual_qa.py.
Detect the available Python command: run python3 --version and python --version, then use whichever succeeds. Cache the result for the session.
Model selection:
vqa_model is API-backed, pass it as --model <value>.vqa_model is native or codex, use Step 4A.vqa_model is missing or empty, STOP with verdict: error.bashVQA_MODEL=$(grep -oP 'vqa_model:\s*\K\S+' .godotmaker/config.yaml 2>/dev/null || echo "") MODEL_FLAG="" case "$VQA_MODEL" in "") echo "Missing vqa_model in .godotmaker/config.yaml" >&2; exit 1 ;; native|codex) echo "Use Runtime-Native Execution for vqa_model: $VQA_MODEL" >&2; exit 1 ;; gemini:*|openai:*) MODEL_FLAG="--model $VQA_MODEL" ;; *) echo "Unsupported vqa_model for API-backed visual_qa.py: $VQA_MODEL" >&2; exit 1 ;; esac # Static PYTHON ${CLAUDE_SKILL_DIR}/scripts/visual_qa.py --log ${VQA_LOG:-.vqa.log} $MODEL_FLAG [--context "Goal: ... Requirements: ... Verify: ..."] reference.png screenshot.png # Dynamic PYTHON ${CLAUDE_SKILL_DIR}/scripts/visual_qa.py --log ${VQA_LOG:-.vqa.log} $MODEL_FLAG [--context "..."] reference.png frame1.png frame2.png ... # Question PYTHON ${CLAUDE_SKILL_DIR}/scripts/visual_qa.py --log ${VQA_LOG:-.vqa.log} $MODEL_FLAG --question "the question" screenshot.png [frame2.png ...]
Always pass --log. Use .vqa.log unless the caller provides a log path. Print the script output as your response.
If the configured API-backed model is unavailable and vqa_fallback_model is native or codex, switch to Step 4A and record the fallback in the log entry's model field. If vqa_fallback_model is none, stop with an error.
After runtime-native execution produces output, append a debug log entry:
bashprintf '{"ts":"%s","mode":"MODE","model":"MODEL","query":"QUERY","files":["FILE1","FILE2"],"output":"FIRST_LINE..."}\n' \ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "${VQA_LOG:-.vqa.log}"
Set MODEL to the vqa_model or vqa_fallback_model value used for the call.
Read scripts/criteria.md before choosing the final verdict.
text### Verdict: {pass | fail | warning} ### Reference Match {1-3 sentences: does the game capture the reference's intent: placement logic, scaling, composition, camera?} ### Goal Assessment {1-3 sentences from Task Context. "No task context provided." if none.} ### Issues {If none: "No issues detected." Otherwise:} #### Issue {N}: {short title} - **Type:** style mismatch | visual bug | logical inconsistency | motion anomaly | placeholder - **Severity:** major | minor | note - **Acceptance impact:** blocks acceptance | non-blocking | style-only - **Frames:** {dynamic only: which frames} - **Location:** {where in frame} - **Description:** {1-2 sentences} ### Summary {One sentence.}
Severity: major = must fix. minor = non-blocking, record only. note = cosmetic/style-only, can ship.
text### Verdict: {pass | fail | warning} ### Answer {Direct, specific, actionable answer. Reference locations, frames, colors, objects.} ### Visual Evidence {What in the screenshots supports the answer. Reference specific frames and locations.}
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→pass | 7,653 | 37,931 | +396% | 1 | 1 | 0% | 1,217 | 8,094 | +565% | 0 | 0 | — |
case-01 | fail→fail | 13,735 | 6,960 | -49% | 1 | 1 | 0% | 2,241 | 2,445 | +9% | 0 | 0 | — |
case-02 | fail→fail | 25,780 | 6,859 | -73% | 1 | 1 | 0% | 4,200 | 2,479 | -41% | 0 | 0 | — |
case-03 | fail→fail | 9,517 | 7,327 | -23% | 1 | 1 | 0% | 1,621 | 2,453 | +51% | 0 | 0 | — |
case-04 | fail→pass | 7,482 | 4,262 | -43% | 1 | 1 | 0% | 1,159 | 2,747 | +137% | 0 | 0 | — |
case-05 | fail→pass | 9,681 | 5,866 | -39% | 1 | 1 | 0% | 1,407 | 3,086 | +119% | 0 | 0 | — |
case-06 | fail→pass | 10,605 | 3,329 | -69% | 1 | 1 | 0% | 1,253 | 2,609 | +108% | 0 | 0 | — |
case-07 | fail→fail | 19,188 | 5,616 | -71% | 1 | 1 | 0% | 4,407 | 2,506 | -43% | 0 | 0 | — |
case-08 | fail→pass | 15,811 | 6,529 | -59% | 1 | 1 | 0% | 2,544 | 3,271 | +29% | 0 | 0 | — |
case-10 | fail→pass | 13,746 | 23,291 | +69% | 1 | 1 | 0% | 2,496 | 6,059 | +143% | 0 | 0 | — |
case-11 | pass→pass | 13,278 | 5,799 | -56% | 1 | 1 | 0% | 2,237 | 3,037 | +36% | 0 | 0 | — |
case-12 | fail→pass | 14,500 | 2,309 | -84% | 1 | 1 | 0% | 2,333 | 2,304 | -1% | 0 | 0 | — |
case-13 | fail→pass | 7,911 | 16,423 | +108% | 1 | 1 | 0% | 1,185 | 4,189 | +254% | 0 | 0 | — |
case-14 | fail→pass | 12,438 | 3,862 | -69% | 1 | 1 | 0% | 1,748 | 2,539 | +45% | 0 | 0 | — |
case-15 | fail→pass | 9,632 | 10,202 | +6% | 1 | 1 | 0% | 1,580 | 2,951 | +87% | 0 | 0 | — |
case-16 | fail→fail | 17,708 | 2,085 | -88% | 1 | 1 | 0% | 2,547 | 2,289 | -10% | 0 | 0 | — |
case-17 | fail→pass | 15,148 | 2,624 | -83% | 1 | 1 | 0% | 2,094 | 2,376 | +13% | 0 | 0 | — |
case-18 | fail→pass | 15,252 | 2,441 | -84% | 1 | 1 | 0% | 2,168 | 2,329 | +7% | 0 | 0 | — |
case-19 | pass→pass | 10,065 | 3,714 | -63% | 1 | 1 | 0% | 1,377 | 2,595 | +88% | 0 | 0 | — |
case-20 | pass→fail | 10,418 | 3,689 | -65% | 1 | 1 | 0% | 1,704 | 2,615 | +53% | 0 | 0 | — |
case-21 | pass→fail | 5,326 | 6,031 | +13% | 1 | 1 | 0% | 871 | 3,073 | +253% | 0 | 0 | — |
case-22 | pass→fail | 8,221 | 22,514 | +174% | 1 | 1 | 0% | 1,373 | 4,811 | +250% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 17 counted toward the lift figure. The other 5 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 17 comparable cases. 5 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.