-
Notifications
You must be signed in to change notification settings - Fork 2
Themes
A RiptOPL/OPL theme is a folder of images, fonts and one text file — conf_theme.cfg —
that lays out the whole UI on a virtual 640×480 canvas. This page is the complete authoring
reference: every block family, every element type, every property and value token the parser in
src/themes.c actually understands, including this fork's Coverflow carousel and the
two-layer overlay system. Nothing here is invented — if a key isn't listed, the engine ignores it.
i Mental model
A theme is a flat, ordered list of
elements. Each element has a type= and a handful of position/size properties. OPL draws
them back-to-front in file order, scales the 640×480 canvas to the real video mode, and (with
scaled=1) corrects for widescreen and the PS2's non-square pixels automatically. Anything a
theme doesn't supply falls back to OPL's embedded default assets.
Themes live in the THM support folder. Each theme is its own sub-folder whose name
must start with thm_; the loader strips that prefix to form the name you see in the theme
picker. Inside the folder, all the artwork/fonts sit alongside a single conf_theme.cfg.
THM/
thm_MyTheme/
conf_theme.cfg ← the layout (this page)
incebtion.png ← background, fonts, case art, screenshots… (any names you reference)
case.png
myfont.ttf
RiptOPL also ships two built-in themes you can study as references without copying any files:
the classic <OPL> theme and this fork's default <Coverflow> theme.
Their sources are misc/conf_theme_OPL.cfg and misc/theme_coverflow.cfg in the
repository — both are reproduced and annotated lower down.
conf_theme.cfg is a plain key/value file with exactly two kinds of line:
-
Global (top-level) properties — bare
key=valuelines, written before any block. -
Element blocks — a
blockname:header line followed by indentedkey=valuelines.
# lines beginning with '#' are comments — comment a whole block to disable it
bg_color=#182580 # a global property
main0: # an element block
type=Background
pattern=BG
i Block keys are flattened
Internally a block property
foo under block main0 is read as the key main0_foo. You almost always
write the indented form above, but knowing this explains the flat tables in §3–§4 — every "property" is just a
<block>_<property> key.
Element block names carry a family prefix plus an index — e.g. main0, main1,
appsMain2, vcdInfo3. Each family targets one screen/view. The base families are
main<N> (the games list/menu page) and info<N> (the game
info page). On top of those, this fork adds three per-slot override families. For every slot
N the engine looks for the family's block; if it's absent it falls back down a fixed
chain — so you override only what differs and inherit the rest.
| Family (main / info) | Drawn on | Per-slot fallback chain |
|---|---|---|
main0… / info0…
|
The games list / info — the base layout | (none — this is the base) |
appsMain0… / appsInfo0…
|
The apps device list / info | → mainN / infoN
|
favsMain0… / favsInfo0…
|
The Favorites tab list / info | → mainN / infoN
|
vcdMain0… / vcdInfo0…
|
A device's PS1 / VCD view (toggle with L3), plus every PS1 row's cover and info wherever it appears | main: → appsMainN → mainN · info: → infoN
|
favsVcdMain0… / favsVcdInfo0… (opt-in)
|
The Favorites PS1 view, plus PS1 covers and info on the Favorites All in One shelf | main: → vcdMainN → appsMainN → mainN · info: → vcdInfoN → infoN
|
favsAppsMain0… / favsAppsInfo0… (opt-in)
|
The Favorites ELF view, plus app covers and info on the Favorites All in One shelf | main: → favsMainN → mainN · info: → favsInfoN → infoN
|
The parser reads as many base main<N> blocks as you define, then for each slot
0…N resolves every family against that chain. Practically:
- A theme with only
main*/info*blocks looks identical on the games, apps, Favorites and PS1 views — every family inherits the base. - Define
appsMain5to give the apps cover its own (square) box while games keep their portrait box; everything else still inheritsmain*. - The VCD/PS1 main family falls back to
appsMainbeforemain, so a PS1 disc with novcdMainblocks automatically uses the square apps box (jewel-case art is square), whilevcdInfofalls back to the rich gameinfopage. - The Favorites per-kind families (
favsVcd*,favsApps*) are opt-in: a family exists only if the theme declares at least one of its blocks. They give PS1 and app favorites their own layout, list and cover proportions without touching the device pages. Undeclared slots fall back to the blocks those Favorites views used before. A cover is taken from them only where you declared it, so an undeclared cover keeps today's square PS1 or app cover rather than a copy offavsMain's portrait case, and it is only used where the page draws the same kind (a declared Coverflow styles a carousel, never an ItemCover panel). Their lists take none of the four global list slots, and PS1 / app favorites keep sharing their existing cover caches.
A mixed list holds more than one kind of media at once — the Favorites All in One shelf, and a
device page under PS2/PS1 Game Display = Mixed. The page as a whole still renders from one family (the base
main* on a Mixed device page, favsMain* on Favorites): the background, the texts and the
ItemsList belong to the page, so they stay put while you scroll.
The cover does not. A PS2 case is portrait, a PS1 case and an app box are square, and forcing one shape
on all three stretches whichever kinds are not the page's own. So the cover element — the ItemCover
panel, the Coverflow carousel — is resolved per row, by media kind:
| Row | Cover drawn from |
|---|---|
| PS2 disc game | the page's own family — main2 on a device page, favsMain2 on Favorites |
| PS1 / VCD |
vcdMain* → appsMain* → main*; on Favorites, a cover declared in favsVcdMain* first |
| App / ELF |
appsMain* → main*; on Favorites, a cover declared in favsAppsMain* first |
Only the cover is redirected — its width/height, overlay/overlay2
and default placeholder. Everything else on the page is untouched, and on a single-kind page the row's
kind is the page's kind, so nothing is redirected at all. The same rule picks the info screen's cover from
the matching *Info* family. In a Coverflow carousel the cover width stays uniform (so spacing
stays even) and only the height follows each row's own element aspect.
ℹ Two cover caches on a mixed list
The games, apps and Favorites
families share one cover-art cache (deduplicated by pattern), while the PS1/VCD view keeps its
own — separate PS2 and PS1 views reuse the device's game list indices, so a shared cache would thrash
covers on every toggle. A mixed list therefore draws from two caches at once, PS1 rows from the VCD one and
everything else from the shared one, and both are warmed.
⚠ Contiguous-numbering rule
Blocks are read in order from 0
and the engine stops at the first gap. If you define main0, main1,
main3 (skipping main2), then main3 is never read. When you delete
a block, renumber the ones after it so there are no holes. The same applies inside each info*
sequence. (A commented-out block counts as a deletion — re-number around it.)
Why does a Background have to be element 0?
The first element of a list must be the Background (the engine inserts a default plasma
background if you forget). Likewise only the first ItemsList becomes the games list, the second the
apps list, the third the Favorites list and the fourth the PS1/VCD list — so order matters beyond just draw
order. The PS1/VCD slot is optional: define only three lists and the PS1 view falls back to the games list,
sharing its cover cache. Give it a fourth and it gets its own.
These go at the top of the file, outside any block.
| Key | Applies to |
|---|---|
bg_color |
Plasma / background tint (the gradient's HIGH end) |
plasma_blend_color |
Plasma gradient LOW end — defaults to black, which reproduces the historical look |
text_color |
Default element text colour |
ui_text_color |
UI text (menus, buttons, hints) |
sel_text_color |
Selected-item text colour |
Colours are 8 bits per channel in hex; alpha is fixed internally (the parser sets it for you).
| Key | Value | Notes |
|---|---|---|
default_font |
font file path | The theme's main font; falls back to the built-in font if the file is missing. |
font1 … font15
|
font file path | Extra fonts; each defaults to default_font if not set. |
default_font_size |
int (px) | Size for the default font (defaults to the system default if ≤ 0). |
font1_size … font15_size
|
int (px) | Per-font sizes. |
Reference a font from an element with font=N (0 = default). font1=builtin is
not a real token: the parser builds the path <theme>/builtin, that file doesn't exist, so the
load fails and the slot falls back to the embedded default font. The <Coverflow> theme relies
on this file-not-found fallback (and for the built-in <Coverflow> the font keys aren't parsed at
all, since font loading is skipped for buffer-loaded built-in themes).
| Key | Value | Meaning |
|---|---|---|
use_default |
0 / 1 | Use OPL's embedded default assets for anything the theme omits (default 1). |
use_real_height |
0 / 1 | Lay out against the real screen height instead of the virtual 480. |
use_settings_bg |
0 / 1 | Load the theme's own settings_bg.png behind the settings menus instead of the plasma. Theme-supplied only — there is no embedded default, so the built-in themes leave the plasma in place. |
coverflow_cover_offset |
int (clamped −1024…1024, default 0) | Horizontal nudge for the Coverflow carousel (see §9). |
i Tinting the plasma
The plasma background is a gradient
between two colours: plasma_blend_color is the low end and bg_color the
high end. Setting only bg_color keeps the classic look, because
plasma_blend_color defaults to black. Set both to tint the whole gradient.
Every element block starts with type=<ElementType> (see §5). Almost all of them also
accept these positioning/appearance properties:
| Property | Type | Notes |
|---|---|---|
x |
int or POS_MID
|
Horizontal position. Negative = measured from the right edge. POS_MID = horizontal centre. |
y |
int or POS_MID
|
Vertical position. Negative = measured from the bottom edge. POS_MID = vertical centre. |
width |
int or DIM_INF
|
DIM_INF = full screen width. |
height |
int or DIM_INF
|
DIM_INF = full screen height. |
aligned |
0 / 1 |
0 = anchor top-left; 1 = centre the element on (x, y). |
scaled |
0 / 1 |
0 = raw pixels; 1 = ratio-correct (handles widescreen + pixel aspect). Use 1 for images you want undistorted. |
color |
#RRGGBB |
Text/tint colour. Defaults to text_color. |
font |
0 … 15 | Font index (see §3). Default 0. |
reflection |
0 / 1 | Draw a mirrored, alpha-faded reflection beneath the element (used by Coverflow). Default 0. |
reflection_offset |
int (clamped −1024…1024) | Shift the reflection vertically (e.g. to clear a case base). |
enabled |
0 / 1 | Set 0 to skip the element without deleting the block. Default 1. |
devices |
name list |
This fork. Show the element only on the listed device pages — honoured by MenuIcon, ItemsList and HintText (ignored elsewhere). See Per-device placement. |
Value tokens: POS_MID and DIM_INF (above), and #RRGGBB for
colours. Negative x/y anchor to the right/bottom edge — let those and the tokens do the
work instead of hard-coding resolution-specific numbers.
Set with type=. Elements marked (item) redraw whenever you move the selection.
type= |
Renders |
|---|---|
Background |
Full-screen background. With pattern=BG it draws the plasma; with a default= image it draws that. Must be the first element of its list (auto-added if you omit it). |
StaticImage |
A fixed image from default= (supports overlays). |
StaticText |
Fixed text from value=. |
AttributeText (item)
|
Game metadata text — see attribute= in §6. |
GameCountText (item)
|
The number of items in the current list. |
GameImage (item)
|
Dynamic art from pattern= (cover / screenshot / icon …) with a default= fallback. |
AttributeImage (item)
|
A badge image chosen by a game attribute — see §6. |
MenuIcon |
The current device/menu icon. |
MenuText |
The current menu name, with left/right arrows when there are sibling menus. |
ItemsList (item)
|
The scrolling list of games/apps. First one = games list, second = apps, third = Favorites, fourth = PS1/VCD. Auto-added if omitted. A list with devices= is a per-device override and doesn't count toward those slots. |
ItemIcon (item)
|
A per-item icon element (a GameImage bound to the ICO cache). |
ItemCover (item)
|
The selected item's cover (a GameImage bound to the COV cache), with optional overlay. |
ItemText (item)
|
The selected item's startup filename. |
HintText |
Button hints for the list screen. |
InfoHintText |
Button hints for the info screen. |
LoadingIcon |
The animated loading spinner (only one per theme). |
BdmIndex |
The block-device (BDM) mode indicator — shows which mass device slot is active. |
Coverflow (item)
|
This fork: a centred cover-art carousel (see §9). |
| Property | Used by | Notes |
|---|---|---|
value |
StaticText |
The literal string to show. |
attribute |
AttributeText, AttributeImage
|
The metadata key (§6). |
display |
text |
0 = always show label + value; 1 = only when the value exists; 2 = value only (no label). |
wrap |
text |
1 = word-wrap within width/height. |
title |
AttributeText |
Override the auto-localised label for the attribute. |
| Property | Used by | Notes |
|---|---|---|
decorator |
ItemsList |
A GameImage pattern name (e.g. ICO) to draw as a small per-row icon next to each entry. |
Normally one MenuIcon, one ItemsList and one HintText serve
every device page, so they share a single position. devices= lets a theme place them
differently per device: an element with the key draws only on the listed pages, and an unfiltered
element of the same type automatically stands down there (no key needed on it), staying the default
everywhere else.
# The shared icon spot, used by every page not claimed below.
main3:
type=MenuIcon
x=POS_MID
y=400
# On the MMCE and APA-HDD pages, pin the icon top-right instead.
main4:
type=MenuIcon
devices=mmce,hdd
x=-40
y=24
Device names (comma-separated, case-insensitive):
| Name | Page |
|---|---|
usb |
USB mass storage (any slot) |
ilink |
iLink / FireWire |
mx4sio |
MX4SIO |
hdd_bd |
Internal HDD, exFAT (BDM) |
hdd |
Internal HDD, APA/PFS |
eth |
Network (SMB) |
smb |
Alias of eth
|
mmce |
MMCE / memory-card emulator |
udpbd |
UDPBD network boot |
udpfs |
UDPFS network boot |
app |
The Apps tab |
fav |
The Favorites tab |
bdm |
The generic BDM page before its driver is identified (auto/manual start) |
Rules worth knowing:
-
Only
MenuIcon,ItemsListandHintTexthonour the key; on other element types it parses but has no effect. - Matching follows the page's visible device icon, so a BDM page counts as
usb/mx4sio/… once its driver is identified, and asbdmbefore that. In the PS1/VCD (L3) view the page keeps the device's identity — filters keep working there via thevcdMain*family. - A filtered
ItemsListis an override: it does not consume one of the theme's ItemsList slots (games/apps/favs/VCD, claimed in file order), and navigation/paging automatically follows whichever list is drawn. Give it its ownx/y/height(its row count comes fromheight);decorator=works as usual. -
Keep one unfiltered
ItemsList. If every list in the theme carriesdevices=, OPL adds a plain default list (373×316 at 42,42) on the pages nothing covers — navigation always needs a list — and it won't match your layout. - Unknown device names are logged and skipped; if nothing valid remains, the element behaves as if the key were absent (shared placement) rather than disappearing.
- Two filtered elements of the same type may list different devices; listing the same device twice draws both — that's an authoring error, not a picker.
- Themes without the key are untouched — the filter only activates when
devices=appears.
RiptOPL themes are designed to load on regular/upstream OPL and degrade gracefully — one theme can
serve both. Regular OPL's parser never aborts on fork content: keys it doesn't know
(devices=, reflection_offset, overlay2,
plasma_blend_color, the entire favsMain*, vcdMain*, favsVcdMain*
and favsAppsMain* families…) are
simply never read, and unknown element types (Coverflow) are skipped without stopping the
parse. What to expect there:
- Invisible: all pure-key extras above — regular OPL renders the theme as if they weren't written.
-
Cosmetic:
aligned=2renders centered;#Size/#DiscType/#Systemattributes and the Coverflow carousel are silently absent. -
Ugly but harmless:
devices=layouts — regular OPL draws everyMenuIcon/HintTextblock on every page (overlapping), and treats a secondItemsListas the apps list while still drawing it on the games screen. Per-device layouts are effectively RiptOPL-only. -
⚠ The one rule: always include one plain (unfiltered)
ItemsList. A theme with none — e.g. a Coverflow-only theme, or one where every list carriesdevices=— crashes regular OPL on the first scroll (a latent upstream bug in its default-list repair; RiptOPL fixed it on our side). Ship the plain list and the theme is safe everywhere.
Image-type elements (StaticImage, GameImage, Background,
AttributeImage, ItemCover, Coverflow) add these:
| Property | Type | Notes |
|---|---|---|
default |
asset name | The image to draw / fall back to (a built-in name from §8, or a file in the theme folder). |
pattern |
cache suffix | For dynamic art: COV (cover), SCR / SCR2 (screenshots), ICO (icon), BG (background), … |
count |
int | Number of cache slots for pattern (the engine forces a minimum of 2 for COV). |
overlay |
asset name | An optional frame drawn around the image (a case / bezel). This is layer 1. |
overlay_ulx, overlay_uly
|
int | Upper-left corner of the inlaid art inside the overlay. |
overlay_urx, overlay_ury
|
int | Upper-right corner. |
overlay_llx, overlay_lly
|
int | Lower-left corner. |
overlay_lrx, overlay_lry
|
int | Lower-right corner. |
overlay2 |
asset name | An optional second overlay (layer 2) painted over overlay. It shares the element's position/size and takes no corners of its own. |
The four overlay corners describe where the inner art sits within the overlay frame, in the
element's own coordinate space (relative to width/height). They scale with the drawn
element, so the cover window tracks the art at any size. Omitted corner keys default to 0.
i The two-layer overlay (RiptOPL)
The draw order is
cover → overlay → overlay2. A single asymmetric frame would force the cover
off-centre; splitting the frame into two layers over a centred cover avoids that shift. The fork's
graphics use it as: the cover, then case (the transparent plastic / case frame, layer 1), then
case_overlay (foliage / decoration, layer 2). Both layers are de-duplicated across every element
that names the same asset, so re-using a layer costs no extra VRAM. overlay2 is drawn as a plain
pixmap over the cover composite — it never takes corner coordinates.
For type=AttributeText, set attribute= to a metadata key. The label is
auto-localised (override it with title=):
attribute= |
Shows |
|---|---|
Title |
Game title |
Genre |
Genre |
Developer |
Developer / publisher |
Release |
Release date |
Description |
Long description (use wrap=1 + a width/height box) |
#Size |
Install size — the value is auto-suffixed with MiB
|
For type=AttributeImage, set attribute= to one of the keys below. OPL reads the
game's current value for that attribute; where the glyph comes from depends on the theme:
-
Built-in
<OPL>theme — draws the embedded glyph whose internal name equals the value:#System=PS2→PS2,#Media=CD→CD,#Format=ISO→ISO. Attributes with no embedded glyph (e.g.#DiscType) draw nothing here. -
Disk theme — loads
<value>_<attribute>.pngfrom the theme folder (value first, the same<name>_<suffix>shape as cover art<id>_COV.png):PS2_#System.png,CD_#Media.png,PS2DVD_#DiscType.png. Adefault=gives the fallback badge.
⚠ Disk-theme filename order
The file is
<value>_<attribute>, not <attribute>_<value> —
PS2DVD_#DiscType.png is correct, #DiscType_PS2DVD.png is never read. The
# is a literal filename character, and the extension must be lower-case .png
(the PS2 HDD's filesystem is case-sensitive). These
badges are populated on every device — USB/BDM, SMB, MMCE and the internal HDD/HDL (and their PS1/VCD
lists).
attribute= |
Axis | Value(s) OPL sets | Disk-theme file |
|---|---|---|---|
#System |
Console (FR #49) |
PS1, PS2
|
PS1_#System.png, PS2_#System.png
|
#Media |
Disc type |
CD, DVD (APP for homebrew) |
CD_#Media.png, DVD_#Media.png
|
#DiscType |
Console + media (issue #49) |
PS1CD, PS2CD, PS2DVD
|
PS1CD_#DiscType.png, PS2CD_#DiscType.png, PS2DVD_#DiscType.png
|
#Format |
Image format |
ISO, ZSO, UL, ELF, HDL, VCD
|
ISO_#Format.png, … |
Vmode / Aspect / Scan / Players / Rating
|
Compatibility (value is the full glyph name) |
Vmode_ntsc, Aspect_w, Scan_480p, Players_2, Rating_3, … |
<value>_<attribute>.png |
i #DiscType — one disc glyph per kind
#System
says PS1 vs PS2 and #Media says CD vs DVD, but PS1-CD and PS2-CD both report #Media=CD,
so a single #Media glyph can't tell them apart. #DiscType (issue #49) collapses console
+ media into one token. There are no built-in #DiscType glyphs — supply your own in the theme
folder (PS1CD_#DiscType.png / PS2CD_#DiscType.png / PS2DVD_#DiscType.png)
and give the element a contiguous mainN/infoN index (the parser stops at the
first gap). FR #49 also surfaces #System/#Media on the main page, not just
the info page.
You can point default= or overlay= at any of OPL's embedded textures — no file
needed. (For a theme folder, a same-named file overrides the built-in.)
| Group | Names |
|---|---|
| Covers / art |
cover, coverapp, disc, screen, screens (screenshot overlay), missing
|
| Case overlays |
case (shared frame, layer 1), case_overlay (layer 2, over case), apps_case (legacy apps-only frame) |
| Device icons |
usb, mmce, hdd, eth, app, usb_bd, ilk_bd, m4s_bd, hdd_bd
|
| BDM indicators |
Index_0 … Index_4
|
| Buttons |
cross, circle, triangle, square, left, right, select, start
|
| Loading frames |
load0 … load7
|
| Boot logo |
logo, logo0 … logo6 (animated frames) |
| Backgrounds |
incebtion (default theme bg), ip
|
| Format icons |
ELF, HDL, ISO, ZSO, UL
|
| Media / console |
APP, CD, DVD, PS1, PS2
|
| Aspect / Scan / Vmode / Rating | the badge sets listed in §7 |
settings_bg is theme-supplied only (no embedded default). Legacy Device_* indicators
were removed in this fork — use the device icons and Index_* above.
type=Coverflow (this fork) renders the game/app list as a centred cover carousel with a
reflection and slide animation. It behaves like a GameImage — it uses the same COV
cover cache and overlay/corner system — but draws 3 or 5 covers fanned out around the selection.
The first Coverflow element the parser sees flags the theme as "Coverflow active", which
unlocks the live Coverflow Settings menu.
| Property | Notes |
|---|---|
default |
Fallback cover when a game's art is missing (e.g. cover, or coverapp for the apps list). |
overlay + overlay_* corners |
The case art drawn around each cover (e.g. case). The corners place the cover inside the case window; the engine auto-centres the visible frame and keeps it aspect-correct in both 4:3 and 16:9. |
overlay2 |
The second case layer (e.g. case_overlay), drawn over each cover composite. |
reflection |
1 to draw the mirrored reflection below each cover. Tune with reflection_offset. |
x, y, width, height
|
Carousel position and per-cover size. width/height should match your case art's pixel size so the overlay corners line up; they also set the box aspect. |
⚠ Don't double-correct widescreen
The carousel applies the
widescreen / pixel-aspect correction itself at draw time, exactly like the stock cover path. Author your covers'
aspect via the element's width:height only — never try to pre-stretch them. Games use a
PS2-case portrait box (184×256); apps and PS1/VCD covers use a square box (184×184) to match their
square art. Define a vcdMain Coverflow block to give PS1 covers their own square element; omit it and
PS1 games reuse appsMain (see §2). More than one of these blocks is live at once on a
mixed list, where each row's cover picks the one for its own media kind — so a theme that
overrides favsMain2 should size it as its PS2 cover and define vcdMain2 /
appsMain2 for the other two kinds, rather than leaving the whole shelf on one shape. To give PS1 or app
favorites a carousel of their own, declare a Coverflow block in favsVcdMain* or
favsAppsMain*: the Favorites PS1 / ELF view draws it, and the All in One shelf uses its cover shape for
those rows. A Coverflow block in any family makes the whole theme a Coverflow theme (Left/Right steps
through the list on every browse page), so do this in a theme that already uses Coverflow.
A minimal three-family Coverflow setup (the shape the fork's <Coverflow> theme uses):
main2:
type=Coverflow
default=cover
reflection=1
y=197
width=184
height=256 # portrait PS2 case
overlay=case
overlay2=case_overlay
overlay_ulx=0 overlay_uly=0 overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=256 overlay_lrx=184 overlay_lry=256
appsMain2:
type=Coverflow
default=coverapp
reflection=1
y=239
width=184
height=184 # square apps box
overlay=case
overlay2=case_overlay
overlay_ulx=0 overlay_uly=0 overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=184 overlay_lrx=184 overlay_lry=184
vcdMain2:
type=Coverflow
default=cover
reflection=1
y=239
width=184
height=184 # square PS1 jewel-case box
overlay=case
overlay2=case_overlay
overlay_ulx=0 overlay_uly=0 overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=184 overlay_lrx=184 overlay_lry=184
These live in settings_riptopl.cfg and are exposed in the Coverflow Settings menu (shown
while a Coverflow theme is active). They apply to any Coverflow theme and are clamped on load:
| Config key | Values | Effect |
|---|---|---|
coverflow_count |
3 or 5 | Number of covers shown (anything else is forced to 3). |
coverflow_scale |
px (0…1000) | How much the centre cover grows over the side covers. |
coverflow_anim |
ms (0…5000) | Slide-animation duration; 0 = instant, no animation. |
coverflow_dim |
0 / 1 | Dim the non-centre covers. |
The per-theme horizontal nudge coverflow_cover_offset is the one Coverflow knob that does
live in the theme (a global key — see §3). For the in-menu walkthrough of these settings, see
Coverflow.
All positions/sizes are written for a virtual 640×480 canvas. OPL scales that to the active video mode at draw time — you never hard-code 480p vs. 1080i numbers.
With scaled=1, image
widths are corrected for widescreen and the PS2's non-square pixels, so a square stays square in both
4:3 and 16:9. Positions are not aspect-scaled, so layouts simply fill the wider screen naturally.
Negative x/y anchor to the
right/bottom edge; POS_MID centres; DIM_INF fills. Prefer these over magic numbers so
a layout survives resolution changes.
info3:
type=AttributeText
attribute=Title # the game's title…
color=#ffffff
display=0 # 0 = always show "Title: <value>"
aligned=0 # anchor top-left at (x,y)
x=33
y=70
Switch display=2 to drop the "Title: " label and print the value alone; add
wrap=1 with a width/height box for a long Description.
main5:
type=ItemCover # selected game's cover, COV cache
default=cover # fallback when art is missing
x=-128 # 128px in from the right edge
y=240
overlay=case # layer 1: plastic case frame
overlay2=case_overlay # layer 2: foliage/decoration, over the cover
overlay_ulx=0 overlay_uly=0
overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=256 # cover window = full 184×256 of the frame
overlay_lrx=184 overlay_lry=256
info14:
type=GameImage
pattern=SCR # first screenshot cache
default=screen
x=189
y=-150 # 150px up from the bottom
scaled=1 # any non-zero = ratio-correct (same as 1)
width=200
height=150
overlay=screens # 1px inset bezel around the shot
overlay_ulx=1 overlay_uly=1 overlay_urx=199 overlay_ury=1
overlay_llx=1 overlay_lly=149 overlay_lrx=199 overlay_lry=149
This is the shipped default <OPL> theme (misc/conf_theme_OPL.cfg), annotated.
It is a full, valid conf_theme.cfg — copy it into THM/thm_MyTheme/, edit, and you have
a working theme. Note the contiguous numbering and the single appsMain5 override that swaps the
games' portrait cover box for the apps' square one.
# ── Global colours ───────────────────────────────────────────────
bg_color=#182580 # plasma tint
sel_text_color=#ffffff # selected list row
text_color=#324d9e # default text
ui_text_color=#00FFFF # menus / hints
# ── Games LIST page (main*) ──────────────────────────────────────
main0: # element 0 MUST be the Background
type=Background
pattern=BG # plasma background
main1:
type=StaticImage
default=incebtion # embedded background art
aligned=0
scaled=0
width=DIM_INF # fill the screen
height=DIM_INF
main2:
type=StaticImage
default=ip # small corner image
x=-132 # 132px in from the right
y=20
aligned=0
width=16
height=16
main3:
type=MenuIcon # current device icon
x=0 # (add devices=mmce,hdd,… to place this per device — see §5)
y=0
aligned=0
scaled=0
width=DIM_INF
height=DIM_INF
main4:
type=ItemsList # the scrolling game list (first ItemsList = games)
x=30
y=70
aligned=0
width=400
height=350
main5:
type=ItemCover # selected cover, with the two-layer case frame
default=cover
x=-128
y=240
overlay=case # layer 1 (plastic case)
overlay2=case_overlay # layer 2 (over the cover)
overlay_ulx=0 overlay_uly=0
overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=256 # portrait 184×256 window
overlay_lrx=184 overlay_lry=256
appsMain5: # APPS override of slot 5: square cover box
type=ItemCover
default=coverapp
x=-128
y=-198 # 198px up from the bottom
overlay=case
overlay2=case_overlay
overlay_ulx=0 overlay_uly=0
overlay_urx=184 overlay_ury=0
overlay_llx=0 overlay_lly=185 # square 184×185 window
overlay_lrx=184 overlay_lry=185
main6:
type=LoadingIcon # animated spinner (one per theme)
x=-320
y=-240
main7:
type=BdmIndex # active mass-device slot indicator
x=7
y=-35
width=4
height=32
# ── Game INFO page (info*) ───────────────────────────────────────
info0:
type=Background
pattern=BG
info1:
type=StaticImage
default=incebtion
aligned=0
scaled=0
width=DIM_INF
height=DIM_INF
info2:
type=StaticImage
default=ip
x=-132
y=20
aligned=0
width=16
height=16
info3:
type=AttributeText # Title:
attribute=Title
color=#ffffff
display=0
aligned=0
x=33
y=70
info4:
type=AttributeText # Developer:
attribute=Developer
color=#ffffff
display=0
aligned=0
x=33
y=89
info5:
type=AttributeText # Size: (auto-suffixed " MiB")
attribute=#Size
color=#ffffff
display=0
aligned=0
x=33
y=108
info6:
type=AttributeText # word-wrapped description box
attribute=Description
display=0
color=#ffffff
aligned=0
x=33
y=127
width=590
height=60
wrap=1
info7:
type=AttributeImage # disc badge (CD/DVD/APP)
attribute=#Media
default=APP
width=32
height=16
x=55
y=-252
info8:
type=AttributeImage # format badge (ISO/ELF/…)
attribute=#Format
default=ELF
width=32
height=16
x=86
y=-252
info9:
type=AttributeImage # video-mode badge
attribute=Vmode
default=missing
width=32
height=16
x=117
y=-252
info10:
type=AttributeImage # aspect badge
attribute=Aspect
default=missing
width=32
height=16
x=148
y=-252
info11:
type=AttributeImage # scan-mode badge
attribute=Scan
default=missing
width=32
height=16
x=179
y=-252
info12:
type=AttributeImage # players badge
attribute=Players
default=missing
width=32
height=16
x=210
y=-252
info13:
type=AttributeImage # rating badge
attribute=Rating
default=no_Rating
x=-76
y=-252
width=128
height=16
info14:
type=GameImage # screenshot 1, with a 1px bezel overlay
pattern=SCR
default=screen
x=189
y=-150
scaled=2 # any non-zero = ratio-correct (same as 1)
width=200
height=150
overlay=screens
overlay_ulx=1 overlay_uly=1 overlay_urx=199 overlay_ury=1
overlay_llx=1 overlay_lly=149 overlay_lrx=199 overlay_lry=149
info15:
type=GameImage # screenshot 2
pattern=SCR2
default=screen
x=-191
y=-150
width=200
height=150
overlay=screens
overlay_ulx=1 overlay_uly=1 overlay_urx=199 overlay_ury=1
overlay_llx=1 overlay_lly=149 overlay_lrx=199 overlay_lry=149
Detailed reference: Theme engine: full authoring reference.
Source: themes.html @ fc2e13154e51. Read on the documentation website.
Start here
Storage and networking
- USB, MX4SIO and iLink
- MMCE
- Internal HDD: APA and exFAT
- SMB shares
- Network boot: UDPFS and UDPBD
- HTTP
- NBD server
Games and features
- Neutrino core
- PS1: POPStarter and Ember
- Per-game settings
- Virtual memory cards
- GSM video modes
- In-game reset
- Cheats
- PADEMU
- RetroAchievements
- Apps
Interface and customization
Help and reference
- Troubleshooting
- ZSO format
- Backward-compatible PS3
- Credits and sources
- Features in other forks
- Project overview
Detailed references
- Complete repository guide
- Rolling release reference
- APA hard disk safety and code 402
- Autolaunch and global settings
- Controls reference
- GSM reference
- HTTP reference
- In-game reset reference
- Folders, parental lock and audio
- Language maintenance
- MX4SIO launch reference
- Neutrino reference
- PADEMU reference
- RetroAchievements reference
- Theme engine: full authoring reference
- PS1/VCD reference
- HTTP server conformance tools
- APA recovery tool