t3chnaztea/batocera-skills/batocera-display

Claude Code and agent skill by t3chnaztea/batocera-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when working on how games look on a Batocera cabinet: CRT and other shaders, shaderset resolution and per-game shader overrides, bezel/overlay artwork and alignment, generating missing .info sidecars, filtering unusable bezels, pinning the display resolution, or diagnosing moire and cropped/misaligned game viewports inside bezels. Covers why a shaderset seems invalid, why .info top values are not alpha coordinates, and why Mega-Bezel per-game art fails. Not for performance/framerate tuning (batocera-tuning).

Install

npx vskill@latest install t3chnaztea/batocera-skills/batocera-display

SKILL.md

Batocera Display

Shaders, bezels, and display mode — everything about how the picture looks. Assumes the connection pattern, batocera.conf/configgen model, and verify loop from batocera-ops. Because display changes are visual, the batocera-ops remote verify loop (ES HTTP API launch + batocera-screenshot) is your primary tool here: never declare a shader or bezel "working" from the config alone — launch it and look.

Shaders

Shaders are assigned per-system (or per-game) in batocera.conf. Two key mechanisms and the traps around each.

shaderset resolves against TWO search paths

<system>.shaderset=<name> is a folder-name lookup resolved against both:

  1. /userdata/shaders/configs/<name>/ (user-installed)
  2. /usr/share/batocera/shaders/configs/<name>/ (system-bundled)

Checking only one path is enough to wrongly declare a preset invalid. Some built-in names are aliases that resolve to a preset deep under /usr/share/batocera/shaders/. Before concluding a shaderset value is dead:

bash
SSHB "find /userdata/shaders /usr/share/batocera/shaders -maxdepth 3 -iname '<name>*'"

And read the launch log for the shader actually used on the last launch — it is authoritative:

bash
SSHB "grep -i 'set-shader\|shader' /userdata/system/logs/es_launch_stdout.log | tail"
Two shader keys: shaderset vs -renderer.shader
  • <system>.shaderset=<name> — a Batocera shaderset folder (may bundle bezel

art, e.g. Koko-AIO/Duimon presets).

  • <system>-renderer.shader=<path> — a direct RetroArch .slangp path (relative

to the shaders dir, or absolute). This is how you assign a plain CRT preset like crt/crt-super-xbr or a custom .slangp.

Per-game overrides use the exact-filename key from batocera-ops → batocera-conf: snes["Super Mario World (USA).sfc"]-renderer.shader=.... A glob (snes["Star Fox*"]...) never matches.

Anti-moiré: integer scaling is impossible inside a custom-viewport bezel

A CRT mask shader (crt-royale and friends) can produce rainbow moiré when the game isn't integer-scaled. The usual cure — video_scale_integer — is ignored for a custom viewport, and bezels that force a custom RetroArch viewport (with fractional coordinates) put you exactly there. So you cannot integer-scale inside those bezels.

The workaround is to tame the mask instead of the scale: a wrapper .slangp that #references the CRT preset and sets mask_sample_mode_desired=1 (a scale-tolerant mask sampling mode). Point the arcade systems' -renderer.shader at the wrapper. Verify with before/after screenshots — this is precisely the kind of change that must be seen, not assumed. Full detail in references/shaders.md.

Pin the display mode in batocera.conf, not the boot conf

If a CEC-controlled TV renegotiates EDID on each wake and sometimes lands on 59.94Hz/1080i, pin it: es.resolution=1920x1080.60.00. This must go in /userdata/system/batocera.conf, not /boot/batocera-boot.conf (the boot conf's lower section is auto-synced from batocera.conf on boot and a direct edit gets blanked). Confirm in display.log after a reboot.

Bezels

Bezels/overlays are PNGs with a transparent "cutout" where the game shows, plus a .info sidecar describing the viewport. Packs live under /userdata/decorations/<pack>/, with per-game art at .../games/<system>/<rom>.png (+ .png.info).

.info coordinates are artistic intent, NOT the alpha cutout

The single biggest bezel trap. When a game renders misaligned inside the cutout, the fix is the .info sidecar's top/left/bottom/right — but `top` is not the PNG's transparent-pixel offset. It's where the artist intends the game's viewport edge to sit, often above the alpha cutout because the top bezel artwork is semi-transparent and the game is meant to extend behind it.

Do not derive .info top from the alpha bounding box (autodetecting the transparent region and using that as top moves the game the wrong way). Instead: launch, screenshot, and nudge top in ~20px steps (smaller = game moves up, larger = down). Back up the .info before each iteration. See references/bezels.md.

Generating missing .info sidecars

Some packs (notably thebezelproject) ship thousands of PNGs without .info files. Without a sidecar, configgen guesses a viewport heuristically and often gets it wrong (undersized, top-anchored game). scripts/generate_tbp_info.py alpha-detects each PNG's cutout and writes a correct .info, never overwriting an existing one. This is the correct use of alpha detection — sizing a missing sidecar — as opposed to the misalignment fix above, which is artistic and eyeballed.

Filtering unusable bezels

Some bezels have a cutout so small the game is postage-stamped. scripts/filter_small_bezels.py moves any bezel whose cutout's shorter dimension is below a threshold into a filtered_too_small/ sidecar dir, so Batocera falls back to the pack default. Fully reversible (mv filtered_too_small/* .).

SNES (and similar) fallback strategy

When a pack has per-game art for only a fraction of a large library (e.g. ~50 of ~760 SNES ROMs) and everything else falls back to an ugly generic system bezel, invert the default: set the system to a clean shader-frame look (a Koko-AIO ambilight preset, <system>.bezel=none) and write per-game overrides only for the ROMs that do have real art. scripts/snes-bezel-fallback.py is a ready-to-adapt implementation (idempotent, generates a marker block, backs up batocera.conf).

Don't attempt per-game Mega-Bezel cabinet art

Combining Mega-Bezel's photoreal CRT with per-game cabinet-art bezels is a known dead end on Batocera (stale bezel symlink returns bezel: None, rotation isn't propagated to the shader, and per-game cutout variance can't be bracketed by one global scale offset). The full postmortem — including the false-positive that fools you into thinking it works after one ROM — is in references/bezels.md. Read it before spending a day on this; the short version is don't.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
4
7-day trend score
8

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/t3chnaztea/batocera-skills/batocera-display/badge)](https://verified-skill.com/skills/t3chnaztea/batocera-skills/batocera-display)

Something wrong with this skill or its page? Tell us.