Skin System

Skins let you customize how CA:DE looks — changing panel graphics, colors, icons, and more. This guide walks you through creating your first skin from scratch.

Table of Contents

  1. What is a Skin?
  2. Your First Skin
  3. Folder Structure
  4. The Manifest: skin.json
  5. Writing CSS
  6. Replacing SVG Panels
  7. Player Colors in SVGs and CSS
  8. Adding Images
  9. Skin Options Reference
  10. Asset Keys Reference
  11. Testing and Reloading
  12. Distributing as a ZIP

1. What is a Skin?

A skin is a folder (or ZIP file) containing:

  • A manifest (skin.json) that describes your skin and what it changes
  • One or more CSS files that style UI components
  • SVG files that replace the built-in panel graphics
  • PNG images (e.g., player banners or custom icons)

Skins are layered on top of the default skin. You only need to include what you want to change — everything else falls back to the default.


2. Your First Skin

Step 1 — Create the skin folder

CA:DE automatically discovers skins placed in its data directory. Navigate to:

%AppData%\CaptureAge\

Create a skins folder there if it doesn't already exist, then create your skin folder inside it:

%AppData%\CaptureAge\skins\my-skin\

The folder name is up to you — use something short without spaces.

Step 2 — Create skin.json

At minimum, a skin just needs a name. Create skin.json inside your skin folder:

{
    "name": "my-skin",
    "options": {},
    "stylesheets": [],
    "assets": {}
}

This is a valid (though visually identical to default) skin.

Step 3 — Load your skin in CaptureAge

Restart CaptureAge. Your skin will be discovered automatically and appear in Settings Tab → Select Skin.

Alternative — load from anywhere: You can also load a skin folder or ZIP file from any location on your PC. Go to Settings Tab → Three dots button next to the Select Skin dropdown, choose Folder or ZIP file, then browse to it. This is useful when working on a skin in a different location.


3. Folder Structure

A typical skin folder looks like this:

my-skin/
  skin.json              ← required manifest
  skin.css               ← compiled CSS
  assets/
      bar-panel.svg      ← replacement SVG for the top bar panel
      score-panel.svg    ← replacement SVG for the scoreboard

All paths in skin.json are relative to the skin's root folder.


4. The Manifest

The manifest tells CaptureAge everything about your skin.

Minimal example

{
    "name": "my-skin",
    "options": {},
    "stylesheets": [],
    "assets": {}
}

Full example

{
    "name": "my-skin",
    "options": {
        "alwaysShowUnitPanel": false,
        "standardColorOverrides": []
    },
    "stylesheets": [
        "skin.css"
    ],
    "assets": {
        "assets/ca/bar-panel.svg": "assets/bar-panel.svg",
        "assets/ca/score-panel.svg": "assets/score-panel.svg"
    }
}

Fields

FieldRequiredDescription
nameYesA display name for your skin
optionsYesConfiguration options (can be empty {})
stylesheetsYesArray of CSS file paths to load (relative to skin root). Can be empty.
assetsYesMap of asset keys to file paths (see Asset Keys Reference). Can be empty.

The assets map

Each entry maps an asset key (the identifier CaptureAge uses internally) to a path in your skin folder:

"assets": {
    "assets/ca/bar-panel.svg": "assets/bar-panel.svg"
}

The key on the left is fixed (it must match exactly one of the known asset keys). The value on the right is the path to your replacement file, relative to your skin root. These don't have to be the same — you can organize your files however you like:

"assets": {
    "assets/ca/bar-panel.svg": "panels/my-bar.svg"
}

5. Writing CSS

Add a CSS file to your skin folder and reference it in stylesheets:

"stylesheets": ["skin.css"]

Class name format

CaptureAge uses CSS Modules, but the compiled class names follow a simple, predictable pattern:

.{ComponentFilename}-{localClassName}

For example, the .teamName class inside the Scoreboard becomes .Scoreboard-teamName in the browser. This means you can target any component directly:

.Scoreboard-scoreboard .Scoreboard-teamName {
    color: var(--pcPrimaryBright);
}

.TeamHeader-ageReq .TeamHeader-resReqBars {
    position: absolute;
    bottom: 10px;
}

.EndGame-endGameContainer {
    background-color: #1a1a2e;
    border: 2px solid gold;
}

Discovering class names

The easiest way to find the class names you want to target is to use the built-in skin debugger. In the Settings Tab, check Enable HTTP Server for skin debugging, then click Open Webpage. This opens the live CaptureAge UI in your browser. Use the browser's DevTools inspector (F12) to click on any element and see its exact class names.

Referencing files from your skin

Files in your skin are served relative to your CSS file's location. You can use relative paths in url() directly:

/* file is at the same level as skin.css */
background-image: url(./my-background.png);

/* file is in a subdirectory */
background-image: url(./assets/my-background.png);

The file must be listed in the assets map in skin.json with a key matching the relative path from the skin root.

Loading custom fonts

@font-face {
    font-family: "My Font";
    font-weight: 400;
    src: url(./assets/fonts/MyFont-Regular.ttf) format("truetype");
}

.Scoreboard-scoreboard .Scoreboard-teamName {
    font-family: "My Font", sans-serif;
}

The font file must also be listed in assets:

"assets": {
    "assets/fonts/MyFont-Regular.ttf": "assets/fonts/MyFont-Regular.ttf"
}

Responsive sizing

CaptureAge scales its UI with the window size. Sizes in the compiled CSS are expressed in vw units at standard aspect ratio and with a @media screen and (min-aspect-ratio: 16 / 9) block for ultrawide displays (expressed in vh units). If you need precise sizing, you will typically need both variants.

Limitations

No external CSS — you cannot @import from external URLs. Load everything through the skin's stylesheets array or inline it.


6. Replacing SVG Panels

The main UI panels (bar panel, score panel, dashboard panel, etc.) are SVG files. You can replace them entirely with your own artwork.

How it works

  1. Create your SVG file
  2. Add it to assets in skin.json using the correct asset key
  3. CaptureAge will automatically process your SVG through SVGO (an SVG optimizer)

SVGO processing

All SVGs are automatically processed through SVGO when served. This means:

  • Scripts are removed (for security — this happens to all skins)
  • IDs and class names are both prefixed to avoid clashes between multiple SVGs on the page
  • width and height attributes are removed (the SVG will fill its container)
  • viewBox is preserved — always include a viewBox in your SVG

Important: Because IDs are prefixed, you cannot rely on bare #my-id references within your SVG to survive. SVGO will prefix them to something like #score-panel_svg__my-id. The same applies to class names: class="fillLeft" becomes class="score-panel_svg__fillLeft".

The viewBox aspect ratio determines the panel's rendered height

Since width and height are removed by SVGO, the SVG renders at width: 100% of its container, and its height is calculated from the viewBox aspect ratio. If the ratio is wrong, the panel will visually overflow into other UI elements or appear too small.

Always match your viewBox to the panel's actual dimensions. See Known Panel Dimensions for a reference table.

Targeting SVG elements with CSS

The ID prefix format is based on the SVG's filename. For example, if your SVG file is assets/ca/score-panel.svg, its IDs will be prefixed with score-panel_svg__.

So if your SVG has:

<polygon id="colorBar-left" ... />

After SVGO processing it becomes:

<polygon id="score-panel_svg__colorBar-left" ... />

Your CSS can target it like this:

#score-panel_svg__colorBar-left {
    fill: var(--pcPrimary);
}

Class selectors vs ID selectors

SVGO prefixes both IDs and class names the same way. Some panels in the app use CSS class selectors to target SVG elements — notably bar-panel.svg, which uses classes fillLeft and fillRight for player colors:

<!-- in bar-panel.svg — use class, not id -->
<rect class="fillLeft"  ... />
<rect class="fillRight" ... />
/* in skin.css — class selector, not ID */
.bar-panel_svg__fillLeft  { fill: var(--pcPrimary); }
.bar-panel_svg__fillRight { fill: var(--pcPrimaryAlt); }

Panels with required element IDs

Some panels are used as dynamic bar charts by the app — the components target specific element IDs inside the SVG to drive colors and bar widths. If your SVG is missing these IDs, the dynamic display will not work.

SVG assetRequired element IDs
assets/ca/economy-bar.svgfill_left, fill_right
assets/ca/army-population.svgarmyPopulation-left, armyPopulation-right, armyPopulation-divider, armyPopulation-shadow-center
assets/ca/army-value.svgarmyValue-left, armyValue-right

These IDs follow the same SVGO prefix rule, so fill_left in economy-bar.svg becomes #economy-bar_svg__fill_left in CSS.

Designing SVGs

Use any vector editor (Illustrator, Inkscape, Figma, etc.). A few tips:

  • Always include a viewBox attribute matching the panel's known dimensions (see below)
  • Use classes (.st0, .myClass) on shapes to make CSS targeting easier
  • Give meaningful IDs to elements you want to style dynamically with player colors
  • Remove any embedded scripts — they'll be stripped out anyway

Known Panel Dimensions

Use these exact viewBox dimensions to avoid panels overflowing or appearing too small. Values come from the app's internal size constants.

PanelAsset KeyRecommended viewBox
Balance panel backgroundassets/ca/bar-panel.svg0 0 600 68
Economy balance barassets/ca/economy-bar.svg0 0 600 14
Army population barassets/ca/army-population.svg0 0 600 14
Army value barassets/ca/army-value.svg0 0 600 12
Resources + age (1v1)assets/ca/res-age-panel-1v1.svg0 0 888 57
Resources + age (team games)assets/ca/res-age-panel-tg.svg0 0 544 56
Minimap under/overassets/ca/minimap-*-panel.svg0 0 464 464
Score panel (1v1)assets/ca/score-panel.svg0 0 1254 130
Score panel (team games)assets/ca/score-panel-tg.svg0 0 1254 130

Note: The balance bars (economy-bar, army-population, army-value) are rendered inside the 600×68 balance panel, not as full-width top-bar elements. They are short horizontal bar charts, not background panels.


7. Player Colors in SVGs and CSS

Player colors in CA:DE are dynamic — they change based on game state and color assignment. The skin system exposes them as CSS custom properties that you can use anywhere in your CSS.

Available CSS custom properties

These properties are set by the game on the wrapping element of each player panel:

CSS Custom PropertyDescription
--pcPrimaryMain player color
--pcPrimaryBrightBrighter version of the main color
--pcSecondarySecondary/accent shade
--pcDarkDarker shade
--pcFadeFaded/transparent-ish shade

For 1v1 panels that show both players simultaneously, a second set of properties is available for the "alt" (opposing) player:

CSS Custom PropertyDescription
--pcPrimaryAltOpposing player's main color
--pcPrimaryBrightAltOpposing player's bright color
--pcSecondaryAltOpposing player's secondary color
--pcDarkAltOpposing player's dark shade
--pcFadeAltOpposing player's fade shade

Using player colors in CSS

.playerName {
    color: var(--pcPrimaryBright);
    border-bottom: 2px solid var(--pcDark);
}

Using player colors in SVG elements

To apply dynamic player colors to elements within your SVG panel, target their (prefixed) IDs from your skin's CSS:

/* in skin.css */
#score-panel_svg__colorBar-left {
    fill: var(--pcPrimary);
}

#score-panel_svg__colorBar-right {
    fill: var(--pcPrimaryAlt);
}

8. Adding Images

You can include PNG (or other image format) files in your skin. Note that if the asset key starts with assets CA:DE will try to find its own asset with that name and might throw an error.

"assets": {
    "images/background.png": "images/background.png"
}
.myBackground {
    background-image: url(skin://get/my-skin/images/background.png);
}

9. Skin Options Reference

Set these in the options field of skin.json.

alwaysShowUnitPanel

"alwaysShowUnitPanel": true

When true, the unit detail panel stays visible even when no unit is selected. Useful for always-on overlay layouts.

standardColorOverrides

You can override the color palette used for each player color (Blue, Red, Green, etc.) via standardColorOverrides in skin.json. This changes how those colors appear throughout the UI — in text, borders, SVG fills, minimap dots, and so on.

Structure

Each override targets a specific color ID and replaces one palette key with a hex color:

"standardColorOverrides": [
    { "id": "gameBlue",  "key": "primary",      "color": "#3399ff" },
    { "id": "gameBlue",  "key": "primaryBright", "color": "#66bbff" },
    { "id": "gameBlue",  "key": "dark",          "color": "#1155aa" },
    { "id": "gameRed",   "key": "primary",       "color": "#ff3333" }
]

Color IDs

Game player colors:

IDDefault game color
gameBlueBlue player
gameRedRed player
gameGreenGreen player
gameYellowYellow player
gameTealTeal player
gamePinkPink player
gameGreyGrey player
gameOrangeOrange player
gameGaiaGaia (neutral)

Special colors:

IDUsage
clownFallback/placeholder color
teamNeutralATeam neutral color A
teamNeutralBTeam neutral color B

Palette keys

KeyUsed for
primaryMain UI color for this player (borders, fills, --pcPrimary)
primaryBrightBrighter accent (--pcPrimaryBright)
secondarySecondary shade (--pcSecondary)
darkDark shade for backgrounds (--pcDark)
fadeFaded/semi-transparent appearance (--pcFade)
minimapColor of player's units on the minimap
minimapDarkDarker minimap color
iconMultiplyMultiply blend color for player-colored icons

10. Asset Keys Reference

These are all the assets that can be replaced in a skin. Use the key exactly as shown in your skin.json assets map.

Note: Assets marked not overridable cannot be replaced by a skin.

Main UI Panels (SVGs)

Asset KeyDescription
assets/ca/bar-panel.svgTop bar panel background
assets/ca/economy-bar.svgEconomy bar panel
assets/ca/dashboard-panel.svgDashboard/stats panel background
assets/ca/dashboard-over-panel.svgDashboard overlay layer
assets/ca/selection-panel.svgUnit selection panel background
assets/ca/selection-over-panel.svgUnit selection overlay
assets/ca/score-panel.svgScore/scoreboard panel (1v1)
assets/ca/score-panel-tg.svgScore panel (team games)
assets/ca/score-over-panel.svgScore panel overlay
assets/ca/score-no-teams-panel.svgScore panel (no teams mode)
assets/ca/minimap-under-panel.svgMinimap underlay
assets/ca/minimap-over-panel.svgMinimap overlay
assets/ca/minimap-over-panel-pompeii.svgMinimap overlay (Pompeii game type)
assets/ca/res-age-panel-1v1.svgResources and age panel (1v1)
assets/ca/res-age-panel-tg.svgResources and age panel (team games)
assets/ca/army-population.svgArmy / population display
assets/ca/army-value.svgArmy value display
assets/ca/victory-screen.svgVictory/defeat screen
assets/ca/table-icons-bar.svgStats table icon bar
assets/ca/team-positions-1.svgTeam position display (1 player)
assets/ca/team-positions-2.svgTeam position display (2 players)
assets/ca/team-positions-3.svgTeam position display (3 players)
assets/ca/team-positions-4.svgTeam position display (4 players)

Pompeii-specific (SVGs)

Asset KeyDescription
assets/ca/pompeii/res-age-panel-1v1.svgResources/age panel (Pompeii 1v1)
assets/ca/pompeii/d3-bg-left.svgD3 background left (Pompeii)
assets/ca/pompeii/d3-bg-right.svgD3 background right (Pompeii)
assets/ca/pompeii/d3-age1.svgD3 age 1 graphic (Pompeii)
assets/ca/pompeii/d3-age2.svgD3 age 2 graphic (Pompeii)
assets/ca/pompeii/d3-age3.svgD3 age 3 graphic (Pompeii)
assets/ca/pompeii/PompeiiCountdown-BG.svgPompeii countdown background

CA Icons (SVGs)

Asset KeyDescription
assets/ca/icon/question-mark.svgQuestion mark icon
assets/ca/icon/food.svgFood resource icon
assets/ca/icon/wood.svgWood resource icon
assets/ca/icon/stone.svgStone resource icon
assets/ca/icon/gold.svgGold resource icon
assets/ca/icon/pop-cap.svgPopulation cap icon
assets/ca/icon/kills.svgKills icon
assets/ca/icon/deaths.svgDeaths icon
assets/ca/icon/eco-kills.svgEco kills icon
assets/ca/icon/eco-deaths.svgEco deaths icon
assets/ca/icon/dead-unit.svgDead unit icon
assets/ca/icon/killed-value.svgKilled value icon
assets/ca/icon/creation-value.svgCreation value icon
assets/ca/icon/military-value.svgMilitary value icon
assets/ca/icon/military-building.svgMilitary building icon
assets/ca/icon/castle.svgCastle icon
assets/ca/icon/relic.svgRelic icon
assets/ca/icon/wonder.svgWonder icon
assets/ca/icon/trade-cart.svgTrade cart icon
assets/ca/icon/trade-workshop.svgTrade workshop icon
assets/ca/icon/swords.svgSwords icon
assets/ca/icon/town-center.svgTown center icon
assets/ca/icon/town-center-idle.svgTown center idle icon
assets/ca/icon/hammer.svgBuilder/hammer icon
assets/ca/icon/hammer-idle.svgIdle builder icon
assets/ca/icon/lazy-figure.svgIdle villager icon
assets/ca/icon/garrison.svgGarrison icon
assets/ca/icon/melee-armor.svgMelee armor icon
assets/ca/icon/melee-damage.svgMelee damage icon
assets/ca/icon/pierce-armor.svgPierce armor icon
assets/ca/icon/pierce-damage.svgPierce damage icon
assets/ca/icon/range.svgRange icon
assets/ca/icon/damageDealt.svgDamage dealt icon
assets/ca/icon/damageTaken.svgDamage taken icon
assets/ca/icon/health-regen.svgHealth regen icon
assets/ca/icon/conversions.svgConversions icon
assets/ca/icon/kills-and-conversions.svgKills + conversions icon
assets/ca/icon/heresy.svgHeresy icon
assets/ca/icon/ecoConvert.svgEco conversion icon
assets/ca/icon/buy-sell.svgBuy/sell icon
assets/ca/icon/chest-res.svgChest/resources icon
assets/ca/icon/percent-gold.svgPercent gold icon
assets/ca/icon/sent-received.svgSent/received icon
assets/ca/icon/cross.svgCross/close icon
assets/ca/icon/absolute.svgAbsolute value icon
assets/ca/icon/percent-of-current.svgPercent of current icon
assets/ca/icon/percent-of-max.svgPercent of max icon
assets/ca/icon/eye-combined.svgFOW combined view icon
assets/ca/icon/eye-full-fow.svgFull fog of war icon
assets/ca/icon/eye-no-fow.svgNo fog of war icon
assets/ca/icon/eye-spy-fow.svgSpy fog of war icon
assets/ca/icon/building-req.svgBuilding requirement icon
assets/ca/icon/castle-req.svgCastle requirement icon
assets/ca/icon/nolt.svgNolt feedback icon
assets/ca/icon/aoe2-slash.svgAoE2 separator icon
assets/ca/icon/check-outline.svgCheckmark outline icon
assets/ca/icon/skull-outline.svgSkull outline icon
assets/ca/icon/times-outline.svgTimes/X outline icon
assets/ca/icon/artifact-icon.svgArtifact icon (Pompeii)
assets/ca/icon/ruins-icon.svgRuins icon (Pompeii)

Mini icons (served as URLs)

Asset KeyDescription
assets/ca/icon/mini-tc.svgMini town center icon
assets/ca/icon/mini-wonder.svgMini wonder icon
assets/ca/icon/mini-castle.svgMini castle icon
assets/ca/icon/mini-trade-workshop.svgMini trade workshop icon
assets/ca/icon/mini-king.svgMini king icon
assets/ca/icon/mini-king-garrisoned.svgMini garrisoned king icon

King status icons

Asset KeyDescription
assets/ca/icon/king-status/dead.svgKing dead
assets/ca/icon/king-status/refuge.svgKing in refuge
assets/ca/icon/king-status/threatened.svgKing threatened
assets/ca/icon/king-status/transport-ship.svgKing on transport ship
assets/ca/icon/king-status/under-attack.svgKing under attack

Notification icons

Asset KeyDescription
assets/ca/icon/notification/noti-ship-threatened.svgShip threatened
assets/ca/icon/notification/noti-unboarded.svgUnit unboarded
assets/ca/icon/notification/noti-ungarrisoned.svgUnit ungarrisoned
assets/ca/icon/notification/noti-boarded.svgUnit boarded
assets/ca/icon/notification/noti-garrisoned.svgUnit garrisoned
assets/ca/icon/notification/noti-garrison-threatened.svgGarrison threatened
assets/ca/icon/notification/noti-king-dead.svgKing dead notification
assets/ca/icon/notification/noti-king-threatened.svgKing threatened notification
assets/ca/icon/notification/noti-king-under-attack.svgKing under attack notification

Diplomacy status icons

Asset KeyDescription
assets/ca/icon/diplomacy-status/mutual-ally.svgMutual ally
assets/ca/icon/diplomacy-status/mutual-enemy.svgMutual enemy
assets/ca/icon/diplomacy-status/mutual-neutral.svgMutual neutral
assets/ca/icon/diplomacy-status/one-sided-ally.svgOne-sided ally
assets/ca/icon/diplomacy-status/one-sided-enemy.svgOne-sided enemy
assets/ca/icon/diplomacy-status/one-sided-neutral.svgOne-sided neutral

Speed controls

Asset KeyDescription
assets/ca/controls/bookmark-add.svgAdd bookmark
assets/ca/controls/bookmark-navigate.svgNavigate bookmarks
assets/ca/controls/pause.svgPause
assets/ca/controls/resume.svgResume
assets/ca/controls/skip.svgSkip
assets/ca/controls/speed-default.svgDefault speed
assets/ca/controls/speed-more.svgFaster speed
assets/ca/controls/speed-most.svgFastest speed
assets/ca/controls/speed-slow.svgSlow speed

Age icons (PNGs)

Asset KeyDescription
assets/game/icon/age-1.pngDark Age icon
assets/game/icon/age-2.pngFeudal Age icon
assets/game/icon/age-3.pngCastle Age icon
assets/game/icon/age-4.pngImperial Age icon
assets/game/icon/age-1-pompeii.pngAge 1 (Pompeii)
assets/game/icon/age-2-pompeii.pngAge 2 (Pompeii)
assets/game/icon/age-3-pompeii.pngAge 3 (Pompeii)
assets/game/icon/age-4-pompeii.pngAge 4 (Pompeii)
assets/game/icon/techtree_dark_age.pngDark Age techtree icon
assets/game/icon/techtree_feudal_age.pngFeudal Age techtree icon
assets/game/icon/techtree_castle_age.pngCastle Age techtree icon
assets/game/icon/techtree_imperial_age.pngImperial Age techtree icon
assets/game/icon/techtree_stone_age.pngStone Age techtree icon
assets/game/icon/techtree_tool_age.pngTool Age techtree icon
assets/game/icon/techtree_bronze_age.pngBronze Age techtree icon
assets/game/icon/techtree_iron_age.pngIron Age techtree icon
assets/game/icon/techtree_archaic_age.pngArchaic Age techtree icon
assets/game/icon/techtree_civic_age.pngCivic Age techtree icon
assets/game/icon/techtree_classical_age.pngClassical Age techtree icon
assets/game/icon/techtree_ant_imperial_age.pngAnt Imperial Age techtree icon

Other

Asset KeyDescription
assets/ca/pop-icon-empires1.pngPopulation icon (Empires 1 game type)

Not overridable

The following assets are protected and cannot be replaced by a skin:

  • assets/ca/skin-logo.svg (used for the skin logo feature itself)
  • assets/ca/ca-logo.png
  • assets/ca/ca-logo.svg
  • assets/ca/ca-logo-diamond.svg / .png
  • assets/ca/ca-logo-heart.svg / .png
  • All country flag assets

11. Testing and Reloading

Loading your skin

  1. Open Settings in CA:DE
  2. Go to the Skins section
  3. Select your skin from the dropdown or with the ... selector

The skin loads immediately; errors appear as notifications.

Live reloading during development

CA:DE watches your skin folder for file changes. When you save a CSS or SVG file, the skin reloads automatically — you don't need to restart.

HTTP server — inspect the live UI in your browser

CA:DE includes a built-in HTTP server that serves the live application UI in a regular browser tab. This is the most powerful tool available for skin development.

To enable it: Settings Tab → check Enable HTTP Server for skin debugging → click Open Webpage.

This opens the full CA:DE UI in your browser while a game or recording is running. From there you have access to the browser's complete DevTools:

  • Inspector (F12): Click any element to see its exact compiled CSS class names. This is the fastest way to find the .ComponentName-localClass selectors you need to target in your CSS.
  • Styles panel: See which CSS rules are applied, which are overridden, and edit them live in the browser before writing them to your file.
  • Live editing: Changes you type into DevTools take effect immediately in the browser view, so you can iterate on values (colors, sizes, positioning) without touching any files.

Tip: Keep the browser tab open alongside CA:DE. When you save your skin.css, both the app and the browser tab will hot-reload automatically.

Resolution matters: The browser tab renders at its own viewport size, which may differ from the resolution CA:DE is running at. If you want the browser view to accurately reflect what you see in the app, make sure the browser window is sized to match your CA:DE resolution. Otherwise, the ultrawide screen media query (min-aspect-ratio: 16/9) may activate or deactivate differently in the browser vs. the app, causing layout differences.

Checking for errors

Validation errors (missing files, bad skin.json syntax, invalid asset keys) appear as yellow warning notifications in the app. Check these messages when something doesn't look right.


12. Distributing as a ZIP

Instead of distributing a folder, you can package your skin as a .zip file. Users can load it the same way they load a folder skin.

Creating the ZIP

Zip the contents of your skin folder so that skin.json is at the root of the ZIP (not inside a subfolder):

my-skin.zip
  skin.json          ← must be at root
  skin.css
  assets/
      bar-panel.svg

Not like this:

my-skin.zip
  my-skin/           ← wrong! nested folder
    skin.json
    ...

ZIP requirements

  • skin.json must be at the root
  • All files referenced in skin.json must exist in the ZIP
  • Paths cannot contain .. (no parent directory traversal)
  • Paths cannot be absolute

Quick Reference

Minimal skin.json

{
    "name": "my-skin",
    "options": {},
    "stylesheets": ["skin.css"],
    "assets": {
        "assets/ca/bar-panel.svg": "assets/ca/bar-panel.svg"
    }
}

Player color CSS custom properties

--pcPrimary         --pcPrimaryAlt
--pcPrimaryBright   --pcPrimaryBrightAlt
--pcSecondary       --pcSecondaryAlt
--pcDark            --pcDarkAlt
--pcFade            --pcFadeAlt