Must be read before adding or modifying Oh My PPT slide charts. Defines product-safe Chart.js usage, canvas layout constraints, axis label rules, and retry fixes.
70
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
For deeper examples (chart frame height guide, category axis patterns, layout integration tips), read references/chart.md.
Before writing chart HTML, answer these in order:
h-[Npx] class must equal this final number.Every chart needs exactly two parts: an HTML frame with explicit height, and a script block using DOMContentLoaded + PPT.createChart.
Before writing the chart frame, you MUST calculate the chart slot and then choose the actual chart frame height. Write the calculation as an HTML comment immediately before the chart frame, include the dedicated marker @ppt-chart-height=N, and make the marker, the final chart height, and the h-[Npx] value all use the same number. Never put @ppt-chart-height=... as visible text inside .ppt-chart-frame. Do NOT write a comment that ends with one number and a frame height that uses another number. Two terms: content slot = current canvas height − padding − title − gaps − reserve (the area for the chart plus its support modules); chart slot = content slot − support modules. The final h-[Npx] MUST equal the chart slot, never the content slot.
<!-- height calc @ppt-chart-height=560: default 900 canvas example; content slot = 900 - 48(p-6) - 68(title) - 24(gap-6) - 28(h3) - 8(gap-2) - 32(reserve) = 692 (chart + support area); support rail = 132; chart slot = 692 - 132 = 560 -> h-[560px] -->
<div class="ppt-chart-frame relative h-[560px] w-full overflow-hidden">
<canvas id="my-chart" class="h-full w-full"></canvas>
</div>The final number in the comment and h-[Npx] MUST match. If the comment ends with chart height = 420, the div MUST say h-[420px]; never write chart height = 420 and then use h-[240px].
Use this exact comment structure for generated charts:
<!-- height calc @ppt-chart-height=[final]: content slot = [current canvas height - ... - reserve] = [content slot]; support = [support height]; chart slot = [content slot - support] = [chart slot]; chart height = [role decision] = [final] -->
<!-- Example after replacing placeholders: height calc @ppt-chart-height=560: chart slot = 560; chart height = hero/main = 560 -->
<div class="ppt-chart-frame relative h-[560px] w-full overflow-hidden">Calculation steps:
Column budget rule: columns share width, not height. If the page uses grid-cols-2, the chart column still receives the full post-title vertical content slot. A bad calc is content slot = 732; left metrics = 732/2; right side = 366; the correct calc is right column content slot = 732, then subtract only the right-column heading, insight card, gaps, padding, and reserve.
Do not pair a standard/tall chart with a two-row bottom card grid. If the slide has 4-6 additional facts, choose a density-appropriate structure such as in-chart annotations, one short evidence rail, a compact table, or a grouped list. A main chart usually gets 0-2 support items, not a full card set.
Axis-heavy charts need extra space. For horizontal bars with 6+ categories, long labels, negative+positive ranges, or wide tick labels such as percentages, reserve 40-60px inside the chart options for the x-axis/tick area (layout.padding.bottom, tick padding, and a modest maxTicksLimit). If that would push support modules into a second row, redesign the support area as a side rail, annotation band, compact table, or in-chart callouts instead of shrinking the plot.
Only the .ppt-chart-frame owns chart size. The <canvas> uses class="h-full w-full" and must not have width, height, or inline style size attributes in generated HTML.
Do not mix units or meanings in a single Chart.js dataset or value axis. A bar chart whose x-axis is "变化率 %" must contain only percentages; do not put headcount values such as 850 or 1400 into that same dataset. If the source has both absolute counts and percent changes, choose one expression:
850 on the percent axis.Chart.js category labels are plain text. Do not put HTML such as <br>, <span>, or inline styles inside data.labels; Chart.js will draw that HTML literally or mis-measure it. For multi-line category labels, use string-array labels (e.g. ['AI调校师', '约80→1,400']) or keep details in tooltip callbacks / nearby annotations.
A chart-only slide is usually under-explained even if the chart is large. Pair the main chart with one visible takeaway sentence and, when useful, 1-2 compact annotations, an insight rail, or a source/note line. These support modules explain how to read the chart; they must not repeat every bar/table row as equal-weight cards. If the source has rich context, use the support area for "so what", caveat, baseline, or implication rather than more labels.
Bad patterns to avoid:
<!-- height calc: current canvas height - 48(...) = available content slot -->
<div class="ppt-chart-frame relative h-[400px]">...</div>
<div class="ppt-chart-frame relative h-64">...</div>
<canvas id="chart" width="320" height="380" style="height: 240px"></canvas>
<!-- Mixed units on one percentage axis: 850 people, 1650%, and 17.9% are not comparable -->
data: { labels: ['AI叙事设计师', 'AI调校师', '原画师'], datasets: [{ label: '变化率', data: [850, 1650, 17.9] }] }
<!-- Chart.js labels are not HTML -->
labels: ['AI调校师<br><span>约80→1,400</span>']<script>
document.addEventListener('DOMContentLoaded', function() {
PPT.createChart(document.getElementById('my-chart'), {
type: 'bar',
data: {
labels: ['A', 'B', 'C'],
datasets: [{
label: 'Revenue',
data: [10, 20, 30],
backgroundColor: ['#3B82F6', '#10B981', '#F59E0B']
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'bottom' }
},
scales: {
y: { beginAtZero: true }
}
}
});
});
</script>This is the only correct event and the only correct API. The runtime loads Chart.js before DOMContentLoaded fires, so the helper is always available inside this callback.
<div class="grid grid-cols-2 gap-4">
<div class="flex flex-col gap-2">
<h3 class="text-2xl font-bold">Quarterly Revenue</h3>
<p class="text-lg text-gray-500">Growth trend across regions</p>
</div>
<!-- height calc @ppt-chart-height=560: default 900 canvas example; page content slot = 900 - 48(p-6) - 68(title/subtitle) - 24(gap-6) - 32(reserve) = 728; two columns share width, not height; right-column heading/support = 168; chart slot = 728 - 168 = 560; chart height = hero/main side chart = 560 -->
<div class="ppt-chart-frame relative h-[560px] w-full overflow-hidden">
<canvas id="revenue-chart" class="h-full w-full"></canvas>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
PPT.createChart(document.getElementById('revenue-chart'), {
type: 'bar',
data: {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
datasets: [{
label: 'Revenue (M)',
data: [12, 19, 15, 22],
backgroundColor: '#3B82F6'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: { y: { beginAtZero: true } }
}
});
});
</script>PPT.createChart(canvasElement, config) — pass the canvas DOM element, not a 2D context.PPT.createChart call inside document.addEventListener('DOMContentLoaded', function() { ... }).data.labels as plain strings or string arrays. If a category-axis ticks.callback is needed, return this.getLabelForValue(value)..ppt-chart-frame needs the height calc comment immediately before it..ppt-chart-frame div — it wastes height budget without visual benefit. Padding belongs on the parent card/container, not on the chart frame itself.width, height, or inline style size attributes on <canvas>; the chart frame controls the size.When a chart is blank or broken:
DOMContentLoaded. Any other event name (ppt-ready, ppt-rendered, ppt-page-ready, load, etc.) will not fire or fire too early.getElementById string must match the canvas id attribute exactly.h-[Npx] must be a positive number. A missing or zero height produces an invisible canvas.data array of numbers using one unit/meaning per value axis.DOMContentLoaded listener for the same canvas.Two levels of chart animation, each handled by a different system:
data-anim on the .ppt-chart-frame div. This is a standard layout animation — see animation skill.options.animation. The runtime defaults handle this; you rarely need to customize it.data-anim for the container, and Chart.js options for the internals.data-anim on the chart frame div (see animation skill).d2046bf
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.