From 0f22ffcf4485c648b5d85519cab092345a3f7931 Mon Sep 17 00:00:00 2001 From: Troy O'Leary <84645104+TROY665@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:57:51 +1000 Subject: [PATCH 1/2] Fix: forward theme text colour to chart scenes and theme the comparison card Chart scenes are unreadable on any dark theme. BarChart, LineChart, PieChart and KPIGrid all default `textColor` to #1F2937 (near-black), but Explainer only ever passed them `backgroundColor` - so on a dark theme every title, axis label, category label and value renders dark-on-dark. ComparisonCard has the mirror-image bug: it *does* receive the theme's `textColor`, but hardcodes `cardBackgroundColor = "#F3F4F6"`, painting light text onto a light card. Forward `textColor` to the four chart components, and give ComparisonCard `cut.cardBackgroundColor || theme.surfaceColor` so its surface follows the theme. Adds `cardBackgroundColor?: string` to the Cut interface for a per-cut override. Verified by re-rendering a 7-scene explainer on a dark theme: chart title, y-axis scale, category labels and per-bar values are all legible, and the comparison card labels now show on a themed surface. --- remotion-composer/src/Explainer.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/remotion-composer/src/Explainer.tsx b/remotion-composer/src/Explainer.tsx index 91b0da67..644eb1c4 100644 --- a/remotion-composer/src/Explainer.tsx +++ b/remotion-composer/src/Explainer.tsx @@ -220,6 +220,7 @@ interface Cut { heroSubtitle?: string; // Styling overrides backgroundColor?: string; + cardBackgroundColor?: string; // Inner card surface (comparison); defaults to theme.surfaceColor backgroundImage?: string; // AI-generated or stock image rendered behind the component backgroundVideo?: string; // Video clip rendered behind the component (takes priority over backgroundImage) backgroundVideoStart?: number; // Seek position in seconds for background video (default 0) @@ -602,6 +603,7 @@ const SceneRenderer: React.FC<{ cut: Cut; theme: ThemeConfig }> = ({ cut, theme leftLabel={cut.leftLabel} rightLabel={cut.rightLabel} leftValue={cut.leftValue} rightValue={cut.rightValue} title={cut.title} backgroundColor={bgColor} textColor={textColor} + cardBackgroundColor={cut.cardBackgroundColor || theme.surfaceColor} /> ); } @@ -640,6 +642,7 @@ const SceneRenderer: React.FC<{ cut: Cut; theme: ThemeConfig }> = ({ cut, theme data={cut.chartData} title={cut.title} colors={cut.chartColors || theme.chartColors} animationStyle={(cut.chartAnimation as any) || "grow-up"} showGrid={cut.showGrid} showValues={cut.showValues} backgroundColor={bgColor} + textColor={textColor} /> ); } @@ -650,6 +653,7 @@ const SceneRenderer: React.FC<{ cut: Cut; theme: ThemeConfig }> = ({ cut, theme animationStyle={(cut.chartAnimation as any) || "draw"} showGrid={cut.showGrid} showMarkers={cut.showMarkers} showLegend={cut.showLegend} xLabel={cut.xLabel} yLabel={cut.yLabel} backgroundColor={bgColor} + textColor={textColor} /> ); } @@ -660,6 +664,7 @@ const SceneRenderer: React.FC<{ cut: Cut; theme: ThemeConfig }> = ({ cut, theme animationStyle={(cut.chartAnimation as any) || "expand"} donut={cut.donut} centerLabel={cut.centerLabel} centerValue={cut.centerValue} showLegend={cut.showLegend} backgroundColor={bgColor} + textColor={textColor} /> ); } @@ -669,6 +674,7 @@ const SceneRenderer: React.FC<{ cut: Cut; theme: ThemeConfig }> = ({ cut, theme metrics={cut.chartData} title={cut.title} columns={cut.columns} colors={cut.chartColors || theme.chartColors} animationStyle={(cut.chartAnimation as any) || "count-up"} backgroundColor={bgColor} + textColor={textColor} /> ); } From 9767ff2fb9228adef09503b1278bae017cd06969 Mon Sep 17 00:00:00 2001 From: Troy O'Leary <84645104+TROY665@users.noreply.github.com> Date: Mon, 10 Aug 2026 18:32:10 +1000 Subject: [PATCH 2/2] Add contract tests for chart text colour on dark themes Follows the existing source-assertion style in this file. Both tests fail against the pre-fix Explainer and pass after it: - charts must receive textColor={textColor}, or their labels render dark-on-dark (the components default textColor to #1F2937) - ComparisonCard must get a themed cardBackgroundColor, or its labels render light-on-light (the component hardcodes #F3F4F6) --- ...test_remotion_video_transition_contract.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/contracts/test_remotion_video_transition_contract.py b/tests/contracts/test_remotion_video_transition_contract.py index 3d30934b..a3286717 100644 --- a/tests/contracts/test_remotion_video_transition_contract.py +++ b/tests/contracts/test_remotion_video_transition_contract.py @@ -26,3 +26,43 @@ def test_cinematic_fades_are_bounded_by_each_scene_duration() -> None: assert "Math.round(scene.durationSeconds * fps)" in source assert "durationInFrames - fadeOutFrames" in source + + +def _jsx_block(source: str, component: str) -> str: + """Return the JSX element text for in the source.""" + start = source.index(f"<{component}") + end = source.index("/>", start) + return source[start:end] + + +def test_chart_scenes_receive_the_theme_text_color() -> None: + """Charts default textColor to near-black (#1F2937). + + If Explainer does not forward the theme's textColor, every chart title, + axis label, category label and value renders dark-on-dark and is invisible + on any dark theme. + """ + source = (REPO_ROOT / "remotion-composer/src/Explainer.tsx").read_text( + encoding="utf-8" + ) + + for component in ("BarChart", "LineChart", "PieChart", "KPIGrid"): + assert "textColor={textColor}" in _jsx_block(source, component), ( + f"{component} must receive the theme textColor, " + f"or its labels are invisible on dark themes" + ) + + +def test_comparison_card_surface_follows_the_theme() -> None: + """ComparisonCard hardcodes cardBackgroundColor to a light grey (#F3F4F6). + + On a dark theme it receives the theme's light textColor, so without a + themed card surface the labels are light-on-light. + """ + source = (REPO_ROOT / "remotion-composer/src/Explainer.tsx").read_text( + encoding="utf-8" + ) + block = _jsx_block(source, "ComparisonCard") + + assert "textColor={textColor}" in block + assert "cardBackgroundColor={cut.cardBackgroundColor || theme.surfaceColor}" in block