// Scaffolds and packages themed Splunk custom visualization apps (multi-viz packs). Creates the complete app directory structure, generates theme.js design tokens from a design brief, writes all Splunk conf files, runs the webpack multi-entry build, and produces the deployable tarball. MUST load vp-ref-gotchas before writing any source code.
[HINT] Download the complete skill directory including SKILL.md and all related files
name
vp-create
description
Scaffolds and packages themed Splunk custom visualization apps (multi-viz packs). Creates the complete app directory structure, generates theme.js design tokens from a design brief, writes all Splunk conf files, runs the webpack multi-entry build, and produces the deployable tarball. MUST load vp-ref-gotchas before writing any source code.
vp-create — scaffold and package a viz pack
Cross-plugin rules apply: Dashboard JSON follows ds-create
hard defaults (from splunk-dashboard-studio). SPL follows
spl-gotchas traps (from splunk-spl). Load both before writing.
Demo data — CSV lookups (preferred over makeresults)
Since viz packs are installable Splunk apps, bundle demo data as
CSV lookup files. This produces cleaner SPL, realistic data, and
dashboards that work immediately after install — no index needed.
Use | makeresults only when the data must be dynamic (random
values, current timestamps). For static demo data that shows off
the viz, CSV lookups are always better — cleaner SPL, realistic
values, and no random()%20 artifacts.
savedsearches.conf template
One example search per viz using the bundled lookup data:
[{{PACK_LABEL}} - {{Viz Label}}]search = | inputlookup {{PACK_ID}}_demo_kpis.csv | head 1dispatch.earliest_time = -24h
dispatch.latest_time = now
display.general.type = visualizations
display.visualizations.type = custom
display.visualizations.custom.type = {{PACK_ID}}.{{VIZ_NAME}}
display.visualizations.custom.{{PACK_ID}}.{{VIZ_NAME}}.theme = dark
One block per viz documenting every formatter setting.
Formatter default values: color picker defaults must use the pack's
theme accent token, not a hardcoded hex. In formatter.html, write
value="{{ACCENT}}" where {{ACCENT}} is replaced with the actual
accent hex from the design brief during scaffolding. Never ship a
formatter with generic defaults like value="#1a91a8".
{"name":"{{PACK_ID}}","version":"{{VERSION}}","description":"Multi-entry build for {{PACK_LABEL}}","scripts":{"build":"webpack --mode production","dev":"webpack --mode development --watch"},"devDependencies":{"webpack":"^5.90.0","webpack-cli":"^5.1.4"}}
Alternative: flat AMD build (build_flat.js)
If webpack bundles cause REQUIREJS_ERROR_MESSAGE Script error in
Dashboard Studio v2's sandboxed iframe (see vp-ref-gotchas F11), use
a flat AMD build instead. This is a fallback — try webpack first.
When to use: only if webpack builds produce Script errors in
Dashboard Studio v2 that can't be explained by F1-F9.
Build process
Option A: webpack (default)
cd examples/{{PACK_ID}}/_build
npm install
npm run build
Option B: flat AMD (fallback for DS v2 iframe issues)
cd examples/{{PACK_ID}}/_build
node build_flat.js
Use Option B only if webpack bundles cause Script errors in Dashboard
Studio v2 (see vp-ref-gotchas F11). Try Option A first.
Verify every bundle after build:
for viz in ../appserver/static/visualizations/*/visualization.js; doecho"--- $viz ---"head -c 200 "$viz"echodone# Each MUST start with: define(["api/SplunkVisualizationBase"# Each MUST NOT contain: => or const or let
When the build and packaging is complete, ALWAYS print:
✅ Viz pack ready for install
File: {{PACK_ID}}.tar.gz
Path: /full/absolute/path/to/{{PACK_ID}}.tar.gz
Size: XX KB
Vizs: kpi_tile, ring_gauge, area_chart, data_table, content_donut
Install: Upload via Splunk Web → Manage Apps → Install from File
Restart: Required for static images to be served
This tells the user exactly where the file is and what to do with it.
Do NOT skip this output. Do NOT abbreviate the path.
Bundled images
Brand logos, hero images, icons, and other static assets go in
appserver/static/images/ — NOT in the root static/ directory.
Splunk serves appserver/static/ at /static/app/{pack_id}/.
appserver/static/images/
logo.svg (brand logo — SVG preferred for crisp scaling)
logo_dark.svg (dark-background variant if needed)
hero.jpg (hero/background image if applicable)
App icons are the only files that belong in root static/:
NEVER use external URLs for images — they require domain allow-list
configuration and fail in PDF export. Always bundle in
appserver/static/images/.
Splunk restart required after installing the app for new static
files to be served.
Canvas size — ALWAYS 1920 × 1080 minimum
THIS RULE IS REPEATEDLY IGNORED. Agents keep generating 1440×900
or 1440×1100 dashboards. CHECK THE WIDTH BEFORE COMMITTING.
WRONG: "width": 1440 ← looks cramped on every modern monitor
WRONG: "width": 1280 ← wastes 30% of screen real estate
WRONG: "width": 1600 ← awkward on both 1080p and 1440p
RIGHT: "width": 1920 ← fits 100% of target screens
CRITICAL: Layout schema requires tabs+layoutDefinitions wrapper.
Even for single-page dashboards with no tabs, Splunk's schema validator
requires the tabs + layoutDefinitions wrapper. The flat format
("layout": { "type": "absolute", ... }) is rejected. Set
"showTabBar": false to hide the tab bar on single-page dashboards.
Canvas background:layout.options only accepts width and height.
For canvas background color, add a full-canvas splunk.rectangle as the
FIRST item in structure:
Height can exceed 1080 for scrollable dashboards, but width is
ALWAYS 1920. This matches ds-create hard default #0.
{{CANVAS_BG}} comes from the design brief's dark or light palette bg
token. Use it as the fillColor on the viz_canvas_bg rectangle — do
not hardcode a color, and do NOT set it via layout.options.backgroundColor
(that property does not exist in the schema).
Markdown panels in bundled dashboards
splunk.markdown has strict schema validation:
fontFamily — ONLY these 7 values:
Splunk Platform Sans, Splunk Data Sans, Splunk Platform Mono,
Arial, Helvetica, Times New Roman, Comic Sans MS
"type": "custom.ring_gauge" — wrong, custom is not the app id
"type": "ring_gauge" — wrong, missing app id prefix
Missing "backgroundColor": "transparent" — Splunk's panel bg covers the Canvas
backgroundColor on custom viz panels
Every custom viz panel MUST set "backgroundColor": "transparent" at
the viz level. Without this, Splunk renders a default panel background
ON TOP of the Canvas — the viz draws behind it, invisible.
This is the viz-levelbackgroundColor property, NOT a namespaced
option. It sits alongside the namespaced settings in options.
If the user wants a custom background (gradient, panel color), add it
as a configurable setting in the viz source code and renderer — NOT
via the Dashboard Studio backgroundColor property.
Z-order in absolute layout
structure array order = z-order. Earlier items render BEHIND later
items.
Common mistake: putting a splunk.rectangle shadow card AFTER the
viz it's supposed to be behind. The rectangle renders ON TOP and
covers the viz.
Rule: background layers first, then panels/cards, then data vizs,
then overlays (tooltips, badges).
Cache busting — increment build on every update
When you update a viz pack and reinstall, Splunk caches the old
visualization.js. Users see old rendering despite the new code.
Fix: increment build in app.conf on every release:
[install]is_configured = 0build = 2# was 1 → increment on EVERY code change
The browser uses build as a cache key. Same build number = cached.
Different build number = fresh load.
Rule: before packaging, ALWAYS check app.conf and increment build.
Drilldown from custom vizs
Custom Canvas vizs can fire drilldown events that navigate to other
dashboards or set tokens.
// In initialize():this.canvas.addEventListener('click', function(e) {
self._onClick(e);
});
// Click handler:_onClick: function(e) {
var rect = this.canvas.getBoundingClientRect();
var mx = e.clientX - rect.left;
var my = e.clientY - rect.top;
var hit = this._hitTest(mx, my);
if (hit !== null) {
var region = this._hitRegions[hit];
var payload = {
action: SplunkVisualizationBase.FIELD_VALUE_DRILLDOWN,
data: region.drilldownData
};
this.drilldownToPayload(payload);
}
},
The drilldownData object should contain the field name and value:
Compact the JSON (no whitespace) before embedding — XML CDATA
doesn't require escaping but large whitespace wastes file size.
Rule: every time you modify dashboard.json, regenerate the XML.
Stale XML = users install the app and see an old dashboard.
Required cross-plugin skills
Before writing ANY SPL in savedsearches.conf or dashboard JSON data
sources, load spl-gotchas from the splunk-spl plugin. Key
traps that affect viz pack SPL:
#22: tostring() format arg only accepts hex/commas/duration
#23: strftime on _time kills chart x-axis — only use in tables
#2: case() without default returns NULL silently
#5: sort default limit is 10,000 — use sort 0 for unlimited
For full command syntax, read splunk-spl/reference/<command>.md.
When writing dashboard JSON (bundled in default/data/ui/views/),
ALL rules from ds-create in the splunk-dashboard-studio plugin
apply. The most critical hard defaults:
#0: Canvas minimum 1920 × 1080 px — no 1440, no 1280
#6: fontFamily on markdown — only 7 allowed values
#7: fontSize on markdown — only 5 enum values
#8: Markdown panels sized to avoid scrollbars
Also load ds-ref-syntax from splunk-dashboard-studio for the
full Dashboard Studio JSON schema.
The bundled dashboard IS a Dashboard Studio dashboard. Every rule
that applies to ds-create output applies equally to viz pack dashboards.
There is no special exemption for bundled dashboards.
Quality checks after scaffolding
All 5 stanzas in app.conf ([install], [id], [package], [ui], [launcher])
is_configured = 0 (not true)
sc_admin in default.meta global [] stanza
[lookups] stanza with export = system in default.meta
No [triggers] stanza anywhere
theme.js exports ES5 module (var, function, no const/let/arrow)
webpack targets ['web', 'es5'] with all environment flags
All viz dirs contain: formatter.html, visualization.css
savedsearches.conf.spec documents every custom setting