external/ag-shared/prompts/skills/example/ag-charts/quality-rules.md
Mandatory rules for all AG Charts examples. Theme compatibility is the #1 priority.
color:, fill:, stroke:, backgroundColor:#ffffff, #333333, etc.rgb(), rgba(), hsl(), etc.'white', 'black', 'blue', etc. in colour propertiesfontSize, fontWeight, fontFamily, fontStylestyles.css or add any CSS unless absolutely criticalExceptions (extremely rare):
Why this matters: Gallery examples are copied by thousands of developers into different environments. Any hardcoded styling breaks portability across themes, design systems, and containers.
axes.*.type — MUST always be specified for every axis (axes are a dictionary: axes: { x: { type: 'category' }, y: { type: 'number' } })anyAgCartesianChartOptions (cartesian), AgPolarChartOptions (polar), AgFinancialChartOptions (financial). Hierarchy charts (treemap, sunburst) use generic AgChartOptions.renderer, ALWAYS include heading in the return object — omitting it causes an empty line at the top. heading is the primary label (e.g. heading: params.datum.month for cartesian, heading: datum.category for pie/donut). Return { heading, title, data[] }.tooltip: { mode: 'shared' } without a renderer is fine — the built-in shared tooltip handles heading automatically.renderer() — use { heading, title, data[] } object instead (simpler + better styling)// BAD — These add no value over built-in formatting
formatter: ({ value }) => value.toLocaleString();
formatter: ({ value }) => `$${value.toLocaleString()}`;
formatter: ({ value }) => `${value}`;
// BAD — Repetitive nested formatters
axes: [{ type: 'number', label: { formatter: ({ value }) => `$${(value / 1000).toFixed(0)}K` } }],
series: [{ label: { formatter: ({ value }) => `$${(value / 1000).toFixed(0)}K` } }], // Same format!
// GOOD — Single formatter definition at root level
const options = {
formatter: {
y: ({ value }) => `$${(value / 1000).toFixed(0)}K`,
},
// All axes, series, labels, and tooltips use this formatter automatically
};
// GOOD — Root formatter with x and y
const options = {
formatter: {
x: ({ value }) => value.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
y: ({ value }) => `${value.toFixed(1)}%`,
},
};
Only use nested formatters when they differ from the root formatter.
Benefits: DRY principle, consistency across axes/labels/tooltips, single place to update, cleaner code, AG Charts optimises root formatters.
styles.css, NO custom stylesheetsany TypeScript typetheme: 'ag-default') — gallery handles theme switchingseries[].highlightStyle is deprecated — use series[].highlight.*:// DEPRECATED
series: [{ highlightStyle: { fill: 'yellow', strokeWidth: 3 } }];
// MODERN
series: [{ highlight: { highlightedItem: { strokeWidth: 3 } } }];
highlighted boolean is deprecated — use highlightState string:// DEPRECATED
styler: (params) => {
if (params.highlighted) return { strokeWidth: 3 };
};
// MODERN
styler: (params) => {
if (params.highlightState === 'highlighted-item') return { strokeWidth: 3 };
};
Available highlightState values: 'highlighted-item', 'highlighted-series', 'unhighlighted-item', 'unhighlighted-series', 'highlighted-branch', 'unhighlighted-branch', 'none'
itemId is deprecated — use itemType for series item classification:// DEPRECATED (for waterfall, range-area, range-bar, OHLC series)
label: { formatter: ({ itemId, value }) => `${itemId === 'high' ? 'High' : 'Low'}: ${value}` }
// MODERN
label: { formatter: ({ itemType, value }) => `${itemType === 'high' ? 'High' : 'Low'}: ${value}` }
Note: itemId is still valid for legend events where it refers to legend item identifiers, not series datum types.
Shared tooltips (mode: 'shared') → Legend positioning → Axis bands
Axis bands → Data labels → Series styling
Keep single series! → Focus on labels, formatting, bands, tooltips
Navigator + crosshairs + date formatting
Conservative styling + currency formatters + reference lines + right-side Y-axis
MINIMAL axis decoration — maximise visualisation space, avoid footnotes