BarChart value labels misstate non-integer data
Summary
BarChart value labels misstate the data they annotate. formatNumber returns n.toFixed(1) for any non-integer, so a chart of USD costs [0, 0.15, 0.69, 1.33] renders labels 0, 0.1, 0.7, 1.3 while the bars are drawn at the true heights — the graphic and its own annotation disagree, and the chart states numbers that are not the input.
This is a data-correctness bug rather than a styling one, and it is invisible to the pipeline's own quality gate: final_review's visual_spotcheck checks for black frames, broken overlays, missing assets and unreadable text, but never compares rendered chart values against the source data. A chart stating wrong numbers passes self-review with status: pass.
Found while producing a zero-key animated-explainer video whose whole premise was a cost comparison — the chart was quietly wrong in three of four bars.
Environment: commit 08e2151, Python 3.10, Node v26.7.0, playbook flat-motion-graphics.
Operating system
macOS 15 (Darwin 25.6.0), Mac mini M4
Pipeline
animated-explainer
Runtime / renderer
remotion
Steps to reproduce
Render an
Explainercomposition containing abar_chartcut withshowValues: true:{ "id": "costs", "type": "bar_chart", "in_seconds": 0, "out_seconds": 6, "title": "What a finished video costs (USD)", "showValues": true, "chartData": [ { "label": "This video", "value": 0 }, { "label": "Ghibli anim", "value": 0.15 }, { "label": "Product ad", "value": 0.69 }, { "label": "Pixar short", "value": 1.33 } ] }Extract a frame inside that cut and read the value labels above the bars.
Expected behavior
Value labels match the data passed in: 0, 0.15, 0.69, 1.33.
Actual behavior
Labels render 0, 0.1, 0.7, 1.3. Bar heights still use the true values, so the tallest bar is annotated 1.3 while being drawn at 1.33, and 0.15 is annotated as 0.1 — a 33% understatement.
remotion-composer/src/components/charts/BarChart.tsx:279-284:
function formatNumber(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
if (Number.isInteger(n)) return String(n);
return n.toFixed(1);
}Relevant logs or error output
No error is produced. The render exits 0 and final_review returns:
"visual_spotcheck": {
"black_frames_detected": false,
"broken_overlays": false,
"missing_assets": false,
"unreadable_text": false,
"issues": []
},
"status": "pass"
The only way I found this was extracting a frame and reading the chart.Notes
Suggested fix: derive significant digits from the data's magnitude, or expose a valueFormat / decimals prop so callers can state precision. #518 adds exact formatting controls to KPIGrid; BarChart has the same need and is untouched by it.
Workaround in the meantime: express values in integer units (cents rather than dollars) — integers take the String(n) path and render exactly.
Two adjacent items found in the same run, both of which I could not find reported in any open or closed issue/PR — happy to split them out or fold them into a PR:
ProgressBar'strackColordefault#E5E7EBis never forwarded byExplainer, leaving a bright light-grey track on dark playbooks.progressSegments[].valueis a width percentage (segWidth = (seg.value / 100) * 100), so seven equal segments needvalue: 14.29each rather thanvalue: 1. Nothing documents this and the schema does not constrain it; passing1silently fills 7% of the bar.
I can open a PR with the fix plus a contract test if that is welcome.
Source: calesthio/OpenMontage