theme-branding
Skill1 starsChanged 6 months agoMITView on GitHub
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.
In this repository8 other files it gives its agents.
- bi-dash-creatorSkill
- data-source-connectorSkill
- nlq-dashboard-orchestratorSkill
- project-packagerSkill
- query-to-pbipSkill
- semantic-mapperSkill
- visual-generatorSkill
- visual-selectorSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 3 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 19
After query-to-pbip has produced a PBIP and before bi-dash-creator composes the dashboard
- Distinctive: line 101
Every preset and custom theme should reference the official schema for editor IntelliSense + validation:
- Very specific: line 123
If theme = corporate | modern | minimal | dark → copy assets/themes/<theme>.json into the BaseThemes directory
- Very specific: line 124
If theme = custom → copy the user-supplied theme JSON into the BaseThemes directory (validate it first against references/theme-schema.md …
- Very specific: line 125
If theme is omitted or unknown → keep the default CY25SU11.json
- Distinctive: line 129
When the user supplies brand overrides, patch the theme JSON in this order so all surfaces stay consistent:
- Distinctive: line 161
If a logo path was supplied:
- Very specific: line 174
All structural color slots (background, secondaryBackground, foreground, secondaryForeground, tableAccent) and sentiment/diverging slots …
- Very specific: line 182
If the project was previously zipped, re-run query-to-pbip/scripts/package_pbip.py to refresh the archive.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

