From rain-platform-team
Use this skill whenever a user submits, uploads, or shares a card art image for review of a **virtual or digital card** design — checking against Visa Digital Card Brand Standards and Rain's internal requirements. Trigger on phrases like "check this card art", "review my virtual card design", "does this pass", "card submission review", "validate card art", "check the digital card image", "is this compliant", or when a user uploads an image and mentions virtual cards, digital cards, Visa brand guidelines, or card art for digital use. Also use when the user asks for the RGB fallback colors for a virtual card submission. This skill checks technical specs (dimensions, format, DPI calculated from resolution) and visual design compliance against Visa Digital Card Brand Standards (September 2025), including landscape orientation. It always generates an output review image showing the 56px Visa Brand Mark bleed border, suggested RGB fallback colors, and a sample PAN overlay.
How this skill is triggered — by the user, by Claude, or both
Slash command
/rain-platform-team:virtual-card-art-checkerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill reviews virtual/digital card art submissions against Visa Digital Card Brand Standards
This skill reviews virtual/digital card art submissions against Visa Digital Card Brand Standards (September 2025) and Rain's internal requirements. It produces a structured compliance report, suggests RGB fallback color values, and generates a visual output image for review.
⚠️ #1 REJECTION REASON — 56px Visa Brand Mark Margin
The most common reason Visa rejects card art is the Visa Brand Mark (including "VISA" text and the product identifier like "Signature", "Platinum", etc.) being too close to the card edges. The mark must be at least 56px from the nearest edges — even 1px under is a rejection. The Python script now includes a two-pass Visa Brand Mark distance measurement that:
- Locates the mark using brightness + density filtering (separates text from decoration)
- Measures exact pixel distance from the mark to the top/bottom and right card edges
- Reports FAIL if distance < 56px, WARN if 56-58px (borderline)
Borderline placements (56-58px) have been rejected by Visa in practice — treat WARN as a strong signal to adjust. Always visually verify with extreme scrutiny. When in doubt, fail the card — it is better to send back a card for adjustment than to let a borderline case through to Visa and get rejected.
When a user shares a card art image (or multiple images), you will:
Do this even if the user says "quick check" or seems to want a brief review — the full checklist is important and shouldn't be skipped. A card that fails compliance can delay an issuer's launch.
The image can arrive in three ways. Handle each one:
Run the following Python to find the uploads folder and any image files in it — the session name changes every session, so never hardcode it:
import glob, os
# Dynamically find the uploads folder (session name varies every run)
sessions = sorted(glob.glob('/sessions/*/mnt/uploads/'))
uploads_dir = sessions[0] if sessions else None
image_extensions = ['*.png', '*.jpg', '*.jpeg', '*.webp',
'*.PNG', '*.JPG', '*.JPEG', '*.WEBP']
image_files = []
if uploads_dir:
for ext in image_extensions:
image_files.extend(glob.glob(os.path.join(uploads_dir, ext)))
if image_files:
print(f"Found: {image_files}")
else:
print(f"No image files found in: {uploads_dir}")
Use the first image found as the source file for Step 2. If multiple images are present, ask the user which one to check.
If no image file is found in uploads (i.e. the image was pasted inline rather than uploaded via the file picker), do NOT fall back to visual-only mode — instead proceed to inline reconstruction (Step 1B below) to create a working file so the spec checker can run.
Cowork does not write inline-pasted images to disk — they only exist as base64 in the conversation context. To work around this, reconstruct a working PNG file using PIL based on what you can observe visually. This is not pixel-perfect, but it allows the spec checker to run and eliminates ⚠️ Unverified results wherever possible.
Before writing the reconstruction code, visually inspect the image and determine:
visa_platinum_virtual.png)Then run this Python, substituting in your observations:
from PIL import Image
import os
# --- Fill these in based on visual inspection ---
bg_color = (R, G, B) # e.g. (255, 255, 255) for white
color_mode = "RGB" # "RGB" or "RGBA"
width = 1536 # estimated width in pixels
height = 969 # estimated height in pixels
filename = "card_art_inline.png"
# ------------------------------------------------
out_path = f"/tmp/{filename}"
img = Image.new(color_mode, (width, height), bg_color)
img.save(out_path, "PNG", dpi=(72, 72))
print(f"Saved reconstruction to: {out_path} ({width}x{height}, {color_mode})")
Use out_path as the source file for Step 2. In the final report, mark the Dimensions row as
⚠️ Estimated (not ✅ Pass or ❌ Fail) and add a note: "Inline paste — dimensions estimated
visually. Upload via file picker for pixel-accurate verification." All other checks (format,
DPI, visual checklist) can be reported normally.
Try to download the image using Python:
import requests, os, re
url = "<the URL>"
# Try to infer filename from URL
filename = re.split(r'[/?#]', url)[-1] or "card_art_image"
if '.' not in filename:
filename += ".jpg" # fallback extension
out_path = f"/tmp/{filename}"
r = requests.get(url, timeout=15)
r.raise_for_status()
with open(out_path, 'wb') as f:
f.write(r.content)
print(f"Downloaded to {out_path}")
If the URL is behind authentication (e.g., Slack, Google Drive) and the download fails or returns HTML instead of image bytes, use inline reconstruction (Step A2 above). Note the URL source in the report and mark Dimensions as ⚠️ Estimated.
Use the path directly with the spec checker script.
Once you have a file path, locate and run the spec checker script. The script is extracted alongside the skill — find it dynamically (session name changes every run):
import glob, subprocess, sys
# Find the spec checker script — never hardcode the session name
scripts = glob.glob('/sessions/*/virtual-card-art-checker/scripts/check_technical_specs.py')
if not scripts:
scripts = glob.glob('/sessions/*/virtual-card-art-checker-extracted/virtual-card-art-checker/scripts/check_technical_specs.py')
if scripts:
script_path = scripts[0]
result = subprocess.run([sys.executable, script_path, "<path-to-image>"],
capture_output=True, text=True)
print(result.stdout)
else:
print("Script not found — will need to extract from skill zip first")
If the script isn't found, extract the skill zip first:
SKILL_ZIP=$(find /sessions/*/mnt/uploads/ -name "virtual-card-art-checker.skill" 2>/dev/null | head -1)
SESSION_DIR=$(echo "$SKILL_ZIP" | grep -oP '/sessions/[^/]+')
unzip -o "$SKILL_ZIP" -d "${SESSION_DIR}/virtual-card-art-checker/"
This outputs JSON with:
Save the JSON output — you'll use it in the report.
If Pillow isn't installed, the script installs it automatically.
Note: The script no longer generates a separate review PNG. The results PDF (generated in Step 5) is the sole visual output — it contains the card art with bleed border, PAN overlay, color swatches, and all compliance tables in a single document.
With the image in front of you, check each of the following visually. Be thorough — some of these are easy to miss:
Visa Platinum, Visa Signature, Visa Infinite (consumer
cards) or Corporate (business/corporate cards). Rain no longer offers the Classic
tier, so a product identifier is always required — there is no valid case where
it can be absent. The identifier must be placed directly below or immediately
adjacent to the Visa Brand Mark, anchored to the same upper corner (upper-left or
upper-right). Flag as ❌ Fail if: (a) no identifier is visible on the card, (b) the
identifier is in the opposite corner from the Brand Mark, (c) the identifier is
separated from the Brand Mark by unrelated graphics or large empty space, or
(d) the identifier is anywhere in the lower-left personalization zone. Casing
should match the canonical forms; if it deviates (e.g., VISA PLATINUM,
signature), include a ⚠️ note in the result.Only two size options are permitted. Check which one is used and verify it matches:
Option One — Visa Brand Mark with Debit Identifier (for Debit cards):
| Measurement | Value | Description |
|---|---|---|
| C | 109 px | Height of Visa Brand Mark |
| D | 56 px | Distance from nearest card edge to Visa Brand Mark |
| E | 56 px | Distance from baseline of debit identifier to top of Visa Brand Mark |
| F | 50 px | Minimum height of debit identifier |
Option Two — Visa Brand Mark (standalone or with Product Identifier) (for Signature, Platinum, Infinite, etc.):
| Measurement | Value | Description |
|---|---|---|
| C | 142 px | Height of Visa Brand Mark |
| D | 220 px | Distance from top of Visa Brand Mark to baseline of product identifier (when present) |
| E | 56 px | Distance from nearest card edge to Visa Brand Mark |
When visually inspecting, estimate whether the Visa Brand Mark height appears to be approximately 109px (Option One) or 142px (Option Two) relative to the card dimensions. The mark should be roughly 11.2% (Option One) or 14.7% (Option Two) of the card height (969px). If it looks significantly smaller or larger than either option, flag it as ❌ Fail.
The spec checker script extracts and suggests fallback colors automatically. These are YOUR suggestions based on analyzing the card design — the issuer should confirm they match their brand intent.
| Color | What it's used for | How to identify it |
|---|---|---|
| Background color | Shown when the card image can't render (low-bandwidth fallback) | The dominant background/fill color of the card design |
| Foreground color | Variable values like last 4 PAN digits | A color with strong contrast against the background |
| Label color | Static labels on the card (e.g., "Debit", "Credit", account type) | A color readable against the background |
Review the script's suggestions against what you see in the design. If the card has a complex gradient or pattern, note the most representative solid color. Override the script's suggestion in the report if your visual judgment produces a better match.
After completing the visual inspection (Step 3) and reviewing the colors (Step 4), generate the full results image. This combines everything — the card art with location markers, overall status, tech spec table, and visual design compliance table — into a single-page PDF.
Build a JSON object from your visual inspection findings. The structure is:
{
"overall_status": "APPROVED | REQUIRES CHANGES | APPROVED WITH NOTES",
"overall_description": "1-2 sentence summary of findings and what needs fixing",
"visual_checks": [
{
"name": "Check name (from Step 3 checklist)",
"result": "pass | fail | warning",
"notes": "Brief explanation (optional for passes)"
}
]
}
Location-based markers: For any failure or warning where a specific location on the card
caused the issue, add marker_x and marker_y fields (floats from 0.0 to 1.0) to place a
numbered marker on the card art. These fields are only for location-specific issues — not
every failure gets a marker.
marker_x: 0.0 = left edge, 1.0 = right edge of cardmarker_y: 0.0 = top edge, 1.0 = bottom edge of cardExamples of checks that should get markers:
Examples of checks that should NOT get markers:
{
"name": "Visa Brand Mark contrast",
"result": "fail",
"notes": "Silver text on pink background — low contrast",
"marker_x": 0.75,
"marker_y": 0.12
}
Each marker gets an auto-assigned number (1, 2, 3, ...) that appears both on the card and in the Ref column of the Visual Design Compliance table, creating a visual legend.
Save the visual results JSON to a temp file, then call the script with --visual-results-file:
import json, glob, subprocess, sys
visual_results = {
"overall_status": "...", # from your assessment
"overall_description": "...", # from your assessment
"visual_checks": [ ... ] # from your Step 3 inspection
}
# Save to temp file
results_json_path = "/tmp/visual_results.json"
with open(results_json_path, "w") as f:
json.dump(visual_results, f)
# Find the script
scripts = glob.glob('/sessions/*/virtual-card-art-checker/scripts/check_technical_specs.py')
if not scripts:
scripts = glob.glob('/sessions/*/virtual-card-art-checker-extracted/virtual-card-art-checker/scripts/check_technical_specs.py')
if scripts:
script_path = scripts[0]
result = subprocess.run(
[sys.executable, script_path, "<path-to-image>",
"--visual-results-file", results_json_path],
capture_output=True, text=True
)
print(result.stdout)
if result.stderr:
print(result.stderr)
This generates <filename>_card_art_checker_results.pdf in the same directory as the input image.
The script generates a Card Art Checker Results image (<filename>_card_art_checker_results.pdf).
Always show this image to the user using the Read tool. The single-page PNG contains:
Card Art Review Pane (top) — the card art with:
Overall Status — colored badge (green/red/orange) with summary description
Technical Specifications table — dimensions, format, DPI with pass/fail status
Visual Design Compliance table — all visual checks with:
This gives the issuer a complete, self-contained compliance document.
After presenting the results, always offer to open the PDF for the user:
"Would you like me to open the results PDF?"
If the user accepts, open it with: open -a Preview "<path_to_results.pdf>"
Output a report in this exact format. Be direct — issuers need to know exactly what to fix.
File: [filename]
Reviewed against: Visa Digital Card Brand Standards (Sept 2025) + Rain requirements
| Check | Result | Detail |
|---|---|---|
| Dimensions (1536×969px) | ✅ Pass / ❌ Fail / ⚠️ Estimated | Actual: [W×H] or "Could not verify — file not on disk" |
| File format (PNG) | ✅ Pass / ❌ Fail / ⚠️ Unverified | Actual: [format] or inferred from filename/URL |
| DPI (≥72 for digital display) | ✅ Pass / ❌ Fail / ⚠️ Unverified | Calculated: [value] DPI (from pixel width ÷ 3.375″) |
| 56px Margin Zone (Visa Brand Mark) | ✅ Pass / ⚠️ Warn / ❌ Fail | Distance measurement from Visa Brand Mark to card edges. FAIL < 56px, WARN 56-58px (borderline) |
| Check | Result | Notes |
|---|---|---|
| Visa Brand Mark present | ✅ / ❌ | |
| Visa Brand Mark position (upper-left or upper-right only) | ✅ / ❌ | No lower-edge placement allowed |
| Visa Brand Mark size (Option One: 109px / Option Two: 142px height) | ✅ / ❌ / ⚠️ | Must match one of the two allowed size options |
| Visa Brand Mark margin (56px from edges — #1 rejection reason) | ✅ / ❌ | Zero tolerance — any brand mark content past the 56px boundary is a hard fail. Cross-reference with bleed zone analysis. |
| Visa Brand Mark contrast against background | ✅ / ❌ | Both "VISA" and product identifier must be clearly readable |
| Product identifier present and placed | ✅ / ❌ / ⚠️ | Required: one of Visa Platinum / Signature / Infinite (consumer) or Corporate (business), placed directly below/adjacent to the Brand Mark in the same upper corner |
| Issuer logo present | ✅ / ❌ | May bleed to edge — no margin requirement |
| No EMV chip graphic | ✅ / ❌ | |
| No hologram imagery | ✅ / ❌ | |
| No magnetic stripe graphic | ✅ / ❌ | |
| No cardholder name | ✅ / ❌ | |
| No PAN / card number | ✅ / ❌ | |
| No expiry date | ✅ / ❌ | |
| No physical card photography | ✅ / ❌ | |
| Lower-left area clear (no marks/graphics) | ✅ / ❌ | Reserved for PAN personalization — no logos, icons, or text; background patterns/decorative lines OK |
| Design elements clear of product identifier | ✅ / ❌ | No artwork touching Signature/Platinum/Infinite text |
| Landscape orientation | ✅ / ❌ | |
| Full color (not grayscale) | ✅ / ❌ |
These values are suggested by the checker based on analyzing the card design. They serve as fallbacks when the card image cannot render due to low bandwidth or connectivity issues.
| Color Field | RGB Value | Hex | Notes |
|---|---|---|---|
| Background color | rgb([R], [G], [B]) | #RRGGBB | [confirm or note if adjusted] |
| Foreground color | rgb([R], [G], [B]) | #RRGGBB | For last 4 PAN digits + variable values |
| Label color | rgb([R], [G], [B]) | #RRGGBB | For static labels on the card |
⚠️ These colors are suggested based on analyzing the card design. Please confirm with your designer that they match the intended brand colors before submitting.
Results image: [path to _card_art_checker_results.pdf] — full results with markers, tables, and status.
[✅ APPROVED / ❌ REQUIRES CHANGES / ⚠️ APPROVED WITH NOTES]
[1-2 sentence summary. If there are failures, list what needs to be fixed. Be specific.]
pixel_width ÷ 3.375 (ISO ID-1 card width in inches).
For digital display, the Visa minimum is 72 DPI. At the standard 1536px width, this calculates
to ~455 DPI which comfortably exceeds the minimum.Visa Platinum, Visa Signature, or Visa Infinite
for consumer cards; Corporate for business/corporate cards. Rain no longer offers
the Classic tier, so absence of an identifier is an automatic ❌ Fail. The identifier
is part of the Visa product lockup and must be placed directly below or immediately
adjacent to the Visa Brand Mark, in the same upper corner. Common rejections:
identifier missing entirely, identifier drifted into the personalization zone,
identifier in the opposite corner from the Brand Mark, or identifier separated from
the Brand Mark by unrelated artwork. Verifying the correct identifier for the
provisioned product tier requires the program record and is not validated here — but
the presence requirement (at least one of the four) is enforced.Full requirements are in references/visa-requirements.md. Read it if you're unsure about a specific check.
npx claudepluginhub betoiii/betos-plugin-marketplace --plugin rain-platform-teamFetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Applies a firm's KYC/AML rules grid to parsed onboarding records: assigns risk rating, checks required documents, outputs rule outcomes with citations, and routes for escalation.
Generates daily or weekly digests of activity from connected sources (chat, email, docs, tasks, CRM), highlighting action items, decisions, mentions, and project updates.