diff --git a/manim_slides/config.py b/manim_slides/config.py
index d93e27c..69f30e2 100644
--- a/manim_slides/config.py
+++ b/manim_slides/config.py
@@ -8,6 +8,7 @@ from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple, Union
from pydantic import BaseModel, FilePath, PositiveInt, root_validator, validator
+from pydantic.color import Color
from PySide6.QtCore import Qt
from .defaults import FFMPEG_BIN
@@ -150,6 +151,7 @@ class PresentationConfig(BaseModel): # type: ignore
slides: List[SlideConfig]
files: List[FilePath]
resolution: Tuple[PositiveInt, PositiveInt] = (1920, 1080)
+ background_color: Color = "black"
@root_validator
def animation_indices_match_files(
diff --git a/manim_slides/convert.py b/manim_slides/convert.py
index 03f5522..4e867a7 100644
--- a/manim_slides/convert.py
+++ b/manim_slides/convert.py
@@ -321,9 +321,9 @@ class RevealJS(Converter):
# Read more about this:
# https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide#autoplay_and_autoplay_blocking
if slide_config.is_loop():
- yield f''
+ yield f''
else:
- yield f''
+ yield f''
def load_template(self) -> str:
"""Returns the RevealJS HTML template as a string."""
diff --git a/manim_slides/present.py b/manim_slides/present.py
index e635c1c..2e9730b 100644
--- a/manim_slides/present.py
+++ b/manim_slides/present.py
@@ -11,6 +11,7 @@ import cv2
import numpy as np
from click import Context, Parameter
from pydantic import ValidationError
+from pydantic.color import Color
from PySide6.QtCore import Qt, QThread, Signal, Slot
from PySide6.QtGui import QCloseEvent, QIcon, QImage, QKeyEvent, QPixmap, QResizeEvent
from PySide6.QtWidgets import QApplication, QGridLayout, QLabel, QWidget
@@ -105,6 +106,11 @@ class Presentation:
"""Returns the resolution."""
return self.config.resolution
+ @property
+ def background_color(self) -> Color:
+ """Returns the background color."""
+ return self.config.background_color
+
@property
def current_slide_index(self) -> int:
return self.__current_slide_index
@@ -411,6 +417,11 @@ class Display(QThread): # type: ignore
"""Returns the resolution of the current presentation."""
return self.current_presentation.resolution
+ @property
+ def current_background_color(self) -> Color:
+ """Returns the background color of the current presentation."""
+ return self.current_presentation.background_color
+
def run(self) -> None:
"""Runs a series of presentations until end or exit."""
while self.run_flag:
@@ -649,7 +660,9 @@ class App(QWidget): # type: ignore
self.label.setScaledContents(True)
self.label.setAlignment(Qt.AlignCenter)
self.label.resize(self.display_width, self.display_height)
- self.label.setStyleSheet(f"background-color: {background_color}")
+ self.label.setStyleSheet(
+ f"background-color: {self.thread.current_background_color}"
+ )
self.pixmap = QPixmap(self.width(), self.height())
self.label.setPixmap(self.pixmap)
@@ -729,6 +742,9 @@ class App(QWidget): # type: ignore
self.display_width, self.display_height = self.thread.current_resolution
if not self.isFullScreen():
self.resize(self.display_width, self.display_height)
+ self.label.setStyleSheet(
+ f"background-color: {self.thread.current_background_color}"
+ )
@click.command()
@@ -924,8 +940,8 @@ def start_at_callback(
"background_color",
metavar="COLOR",
type=str,
- default="black",
- help='Set the background color for borders when using "keep" resize mode. Can be any valid CSS color, e.g., "green", "#FF6500" or "rgba(255, 255, 0, .5)".',
+ default=None,
+ help='Set the background color for borders when using "keep" resize mode. Can be any valid CSS color, e.g., "green", "#FF6500" or "rgba(255, 255, 0, .5)". If not set, it defaults to the background color configured in the Manim scene.',
show_default=True,
)
@click.option(
@@ -980,7 +996,7 @@ def present(
hide_mouse: bool,
aspect_ratio: str,
resize_mode: str,
- background_color: str,
+ background_color: Optional[str],
start_at: Tuple[Optional[int], Optional[int], Optional[int]],
start_at_scene_number: Optional[int],
start_at_slide_number: Optional[int],
@@ -1005,6 +1021,10 @@ def present(
for presentation_config in presentation_configs:
presentation_config.resolution = resolution
+ if background_color is not None:
+ for presentation_config in presentation_configs:
+ presentation_config.background_color = background_color
+
presentations = [
Presentation(presentation_config)
for presentation_config in presentation_configs
@@ -1048,7 +1068,6 @@ def present(
hide_mouse=hide_mouse,
aspect_ratio=ASPECT_RATIO_MODES[aspect_ratio],
resize_mode=RESIZE_MODES[resize_mode],
- background_color=background_color,
start_at_scene_number=start_at_scene_number,
start_at_slide_number=start_at_slide_number,
start_at_animation_number=start_at_animation_number,
diff --git a/manim_slides/slide.py b/manim_slides/slide.py
index 954d378..8a70e83 100644
--- a/manim_slides/slide.py
+++ b/manim_slides/slide.py
@@ -54,6 +54,14 @@ class Slide(Scene): # type:ignore
self.__loop_start_animation: Optional[int] = None
self.__pause_start_animation = 0
+ @property
+ def __background_color(self) -> str:
+ """Returns the scene's background color."""
+ if MANIMGL:
+ return self.camera_config["background_color"].hex # type: ignore
+ else:
+ return config["background_color"].hex # type: ignore
+
@property
def __resolution(self) -> Tuple[int, int]:
"""Returns the scene's resolution used during rendering."""
@@ -321,7 +329,10 @@ class Slide(Scene): # type:ignore
with open(slide_path, "w") as f:
f.write(
PresentationConfig(
- slides=self.__slides, files=files, resolution=self.__resolution
+ slides=self.__slides,
+ files=files,
+ resolution=self.__resolution,
+ background_color=self.__background_color,
).json(indent=2)
)