Theme branding
Skill bcastelino/powerbi-dashboard-generator/skills/theme-branding
Agent Skills toolkit that turns plain-English requests into fully-formed, branded Power BI Desktop Projects (PBIP). Ten composable skills for source-agnostic semantic modeling, visual generation, and theming.
npx -y skills add bcastelino/powerbi-dashboard-generator --skill theme-brandingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Applies professional themes and corporate branding to a generated PBIP project. This skill should be used after the report files are written and before the final dashboard is delivered, to swap in a chosen theme JSON, register it in report.json, and optionally inject a logo and corporate color palette. Provides four built-in presets (corporate, modern, minimal, dark) and supports custom theme files.
SKILL.md
11.3 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it
Theme & Branding
Apply a professional theme to a generated PBIP project. This skill swaps the default CY25SU11 theme for a chosen theme (preset or custom), updates report.json to reference it, and optionally applies logo / corporate color palette overrides.
This skill follows Microsoft's official report-theme techniques:
See references/theme-schema.md for the full canonical reference.
When to Use This Skill
- After
query-to-pbiphas produced a PBIP and beforebi-dash-creatorcomposes the dashboard - The user requests a specific look ("corporate", "modern", "minimal", "dark", or a brand)
- A custom theme JSON file is supplied
- A logo or color palette needs to be embedded
Inputs
- PBIP project path —
<ProjectName>/directory produced byquery-to-pbip - Theme selector — One of:
corporate | modern | minimal | dark | custom - Custom theme path (optional) — Required when
theme = custom; path to a Power BI theme JSON file - Logo path (optional) — PNG/SVG file to embed as a top-of-page image
- Color overrides (optional) —
{ primary: "#hex", secondary: "#hex", accent: "#hex" }
Built-in Theme Presets
| Preset | Style | Primary | Secondary | Background | Foreground |
|---|---|---|---|---|---|
corporate | Professional, conservative, navy/grey | #1F3864 | #5B9BD5 | #FFFFFF | #333333 |
modern | Bold, high-contrast, teal/coral | #19A0AA | #F15A29 | #F7F7F7 | #222222 |
minimal | Monochrome, lots of whitespace | #444444 | #888888 | #FFFFFF | #111111 |
dark | Dark mode, neon accents | #19F5E2 | #FF6F61 | #1E1E1E | #EEEEEE |
Preset theme JSONs live in assets/themes/. Each preset declares the $schema URL, a full 8-color dataColors palette, all five structural colors (background, secondaryBackground, foreground, secondaryForeground, tableAccent), the four sentiment/diverging slots, the ten core textClasses, and baseline visualStyles for *, page, and cardVisual.
Theme Anatomy (the four authoring surfaces)
A Power BI theme has four layered surfaces. Author each in order; later surfaces override earlier ones.
1. Theme colors — the data palette
dataColors[]— the rotating palette for dynamic series. Provide ≥ 8 entries.good/neutral/bad— KPI sentiment + waterfall increase/decrease/total + conditional formatting sentiment.maximum/center/minimum/null— endpoints for diverging color scales (gradient conditional formatting on tables/matrices).
Dynamic vs. static series: dynamic series (one color per category) are auto-themed. Static series whose color was explicitly picked in the format pane are locked and not overridden by a theme swap. Account for this when planning visual brand consistency.
2. Structural colors — the chrome palette
Five named slots drive non-data colors across page, gridlines, axes, and tables:
background,secondaryBackgroundforeground,secondaryForegroundtableAccent
3. textClasses — typography defaults
Ten text classes cover every label in a Power BI visual: callout, title, header, label, largeLabel, smallLabel, semiboldLabel, boldLabel, largeLightLabel, lightLabel. Each takes fontFace, fontSize (points, 6–72), and color.
4. visualStyles — per-card overrides
Three-level keyed object: visualStyles.<visualType>.<styleName>.<cardName>.
<visualType>—*(default) or a specific name (columnChart,lineChart,cardVisual,tableEx,pivotTable,slicer,page, etc.).<styleName>—*(default style) or a named style preset (see below).<cardName>— formatting card (background,border,title,labels,legend,dataPoint,valueAxis,categoryAxis,outspace, etc.).
Colors inside visualStyles must be wrapped as { "solid": { "color": "#hex" } } — unlike the bare hex strings in theme/structural colors.
Binding to the palette via ThemeDataColor
Inside visualStyles, prefer palette references over hard-coded hex so the visual recolors automatically if the palette changes:
"color": { "solid": { "color": { "expr": { "ThemeDataColor": { "ColorId": 0, "Percent": 0 } } } } }
ColorId is the zero-based index into dataColors; Percent is a tint (positive) or shade (negative).
Style presets (multiple looks per visual type)
A single theme can ship multiple named looks (e.g., Hero vs Mini card styles). Users select presets in the format pane. Define them under visualStyles.<visualType>.<StyleName>:
"cardVisual": {
"*": { /* default */ },
"Hero": { "labels": [{ "fontSize": 48 }] },
"Mini": { "labels": [{ "fontSize": 18 }] }
}
$schema declaration
Every preset and custom theme should reference the official schema for editor IntelliSense + validation:
"$schema": "https://raw.githubusercontent.com/microsoft/powerbi-desktop-samples/main/Report%20Theme%20JSON%20Schema/reportThemeSchema-2.140.json"
Finding Visual Property Names
From Microsoft's Find visual properties, use one of:
$schemaautocomplete in VS Code / a JSON editor- Format pane in Power BI Desktop — card names match
cardName, property labels match property keys after camelCasing - PBIR files — inspect
<Project>.Report/definition/pages/<page>/visuals/<visual>/visual.jsonobjectssection; the keys you see (background,title,labels, …) are exactly thecardNamevalues needed invisualStyles
Workflow
Step 1: Locate the PBIP
Find <ProjectName>.Report/StaticResources/SharedResources/BaseThemes/ inside the project directory. This is where the active theme JSON lives.
Step 2: Select the Theme File
- If
theme = corporate | modern | minimal | dark→ copyassets/themes/<theme>.jsoninto the BaseThemes directory - If
theme = custom→ copy the user-supplied theme JSON into the BaseThemes directory (validate it first againstreferences/theme-schema.md§10 — Validation Rules) - If
themeis omitted or unknown → keep the defaultCY25SU11.json
Step 3: Apply Color & Branding Overrides (Optional)
When the user supplies brand overrides, patch the theme JSON in this order so all surfaces stay consistent:
dataColors[0..2]— setprimary/secondary/accentif provided.tableAccent— mirrorprimaryso tables get the brand accent.titletext class color — useprimaryfor visual titles.good/bad— leave defaults unless the user supplies sentiment overrides (the default green/red are accessibility-tuned).visualStyles.cardVisual.*.labels[0].color— if the card big-number color is hard-coded in the preset, swap toprimary. Prefer rewriting it as aThemeDataColorexpression (ColorId: 0) so future palette swaps cascade automatically.
Preserve all other theme properties (including $schema, textClasses, structural slots not being changed, and existing visualStyles cards).
Step 4: Update report.json
In <ProjectName>.Report/definition/report.json, update the themeCollection.baseTheme.name to match the new theme's name property. Update resourcePackages[].items[] to point at the new theme file path:
"resourcePackages": [
{
"name": "SharedResources",
"type": "SharedResources",
"items": [
{
"name": "<themeName>",
"path": "BaseThemes/<themeName>.json",
"type": "BaseTheme"
}
]
}
]
Step 5: Embed Logo (Optional)
If a logo path was supplied:
- Copy the image into
<ProjectName>.Report/StaticResources/RegisteredResources/<sanitized-name>.<ext> - Register it in
report.jsonunderresourcePackages[]withtype: "RegisteredResources" - On page 1, add a new image visual at the top of the page (suggested position:
x: 20, y: 10, w: 200, h: 60). The image visual references the registered resource by name.
Step 6: Validate (per Microsoft schema)
After modifications, verify:
- Theme JSON parses as valid JSON.
nameis present and matches the file basename and thethemeCollection.baseTheme.nameinreport.json.dataColorshas ≥ 8 entries; each is a 6-digit hex.- All structural color slots (
background,secondaryBackground,foreground,secondaryForeground,tableAccent) and sentiment/diverging slots are valid hex when present. - All
textClasses[*].fontSizevalues are integers in[6, 72]; alltextClasses[*].colorvalues are valid hex. - Colors inside
visualStylesare wrapped as{ "solid": { "color": "#hex" } }(orThemeDataColorexpressions) — never bare hex strings. resourcePackages[].items[].pathfiles all exist on disk.- The default
CY25SU11theme entry is not removed if it's still referenced anywhere.
Step 7: Re-zip (Optional)
If the project was previously zipped, re-run query-to-pbip/scripts/package_pbip.py to refresh the archive.
Resources
assets/themes/corporate.json— Corporate preset themeassets/themes/modern.json— Modern preset themeassets/themes/minimal.json— Minimal preset themeassets/themes/dark.json— Dark preset themescripts/apply_theme.py— End-to-end theme application script (copy theme, patch report.json, validate)references/theme-schema.md— Power BI theme JSON schema reference and validation rules
Error Handling
| Error | Resolution |
|---|---|
| Theme JSON fails schema validation | Stop and surface validation errors to the user |
report.json not found | Verify the PBIP path is correct |
| Logo file not found | Skip logo embedding; warn the user |
| Image visual type not supported by the current report version | Fall back to embedding logo via theme visualStyles |
visualStyles color is bare hex (not wrapped) | Reject — themes silently ignore bare hex inside visualStyles. Wrap as { "solid": { "color": "#hex" } } |
| User reports a visual ignoring the theme | Likely a static series with an explicit color override, or a non-themable property. See references/theme-schema.md §9 Considerations & Limitations |
Considerations & Limitations (from Microsoft docs)
- Locked properties: once a user explicitly picks a color or font in the format pane on a static series, the theme no longer overrides it.
- Non-themable properties: a small set of properties (mostly tied to data binding and certain legacy visuals) cannot be themed at all.
- Custom AppSource visuals may ignore themes or honor only a subset.
- No version field: theme JSON is implicitly versioned by the
$schemaURL date suffix.
Gives 0 of the 12 instructions most design systems skills give in ~2.8k tokens
Counted across 528 of the 534 authors here whose files we hold, read 2026-08-06
- create a custom theme if neededin 54 of 528, across 10 files
- read the corresponding theme filein 54 of 528, across 10 files
- ask which theme to applyin 53 of 528, across 9 files
- show the theme showcasein 53 of 528, across 9 files
- maintain visual identity across all slidesin 50 of 528, across 6 files
- apply the specified colors and fontsin 47 of 528, across 3 files
- get explicit confirmationin 45 of 528, across 1 file
- Generate a design system before codingin 19 of 528, across 6 files
- Maintain at least 4.5:1 color contrast ratioin 19 of 528, across 8 files
- Describe component shapes, colors, shadows, and interaction statesin 18 of 528, across 4 files
- Check Python installation and install if missingin 17 of 528, across 4 files
- Default to html-tailwind if stack is unspecifiedin 17 of 528, across 4 files
Said here and by no other author read
- copy chosen theme file into project
- keep default theme if none chosen
- patch dataColors and tableAccent with brand colors
- update visual titles to use primary color
- register new theme in report.json
- embed supplied logo on first page
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.