Compare commits

...

1 Commits

Author SHA1 Message Date
1da3492732 chore(ci): test builds on multiple oses (#7)
* chore(ci): test builds on multiple oses

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: add tqdm to setup

* chore(ci): test builds on multiple oses

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: install deps in two steps

* fix(bug): allows shape to be 2 or 3 dims

* release new version

* chore(ci): test builds on multiple oses

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* chore(ci): test builds on multiple oses

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: install deps in two steps

* fix: deps string

* fix: ci

* fix: single quote strings

* fix: choco install manimce

* Add pyopengl

* Update test_examples.yml

* fix: custom 3d example for manimgl

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: virtual frame buffer

* fix: add ffmpeg dep

* feat(cli): add skip-all option for testing

* chore(lint): black fmt

* fix: typo in deps

* fix: python -m pip install

* fix: typo

* Update test_examples.yml

* fix: try fix

* fix: pip install --user

* pip install -e

* only on windows

* fix: tmp fix

* fix: typo in int parsing

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update test_examples.yml

* Update __version__.py

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-09-12 12:30:33 +02:00
5 changed files with 215 additions and 34 deletions

100
.github/workflows/test_examples.yml vendored Normal file
View File

@ -0,0 +1,100 @@
on:
pull_request:
paths:
- '**.py'
workflow_dispatch:
name: Test Examples
jobs:
build-examples:
strategy:
matrix:
manim: [manim, manimgl]
os: [macos-latest, ubuntu-latest, windows-latest]
pyversion: ['3.7', '3.8', '3.9', '3.10']
exclude:
# excludes manimgl on Windows because if throws errors
# related to OpenGL, which seems hard to fix:
# Your graphics drivers do not support OpenGL 2.0.
- os: windows-latest
manim: manimgl
# manimgl actually requires Python >= 3.8, see:
# https://github.com/3b1b/manim/issues/1808
- manim: manimgl
pyversion: '3.7'
# We only test Python 3.10 on Windows and MacOS
- os: windows-latest
pyversion: '3.7'
- os: windows-latest
pyversion: '3.8'
- os: windows-latest
pyversion: '3.9'
- os: macos-latest
pyversion: '3.7'
- os: macos-latest
pyversion: '3.8'
- os: macos-latest
pyversion: '3.9'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.pyversion }}
- name: Append to Path on MacOS and Ubuntu
if: matrix.os == 'macos-latest' || matrix.os == 'ubuntu-latest'
run: echo "${HOME}/.local/bin" >> $GITHUB_PATH
- name: Append to Path on Windows
if: matrix.os == 'windows-latest'
run: echo "${HOME}/.local/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install MacOS dependencies (manim only)
if: matrix.os == 'macos-latest' && matrix.manim == 'manim'
run: brew install py3cairo
- name: Install MacOS dependencies
if: matrix.os == 'macos-latest'
run: brew install ffmpeg
- name: Install Ubuntu dependencies
if: matrix.os == 'ubuntu-latest'
run: sudo apt install libcairo2-dev libpango1.0-dev ffmpeg freeglut3-dev xvfb
- name: Install Windows dependencies
if: matrix.os == 'windows-latest'
run: choco install ffmpeg
- name: Install manim on MacOs
if: matrix.manim == 'manim' && matrix.os == 'macos-latest'
run: pip3 install --user manim
- name: Install manim on Ubuntu and Windows
if: matrix.manim == 'manim' && (matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest')
run: python -m pip install --user manim
- name: Install manimgl on MacOs
if: matrix.manim == 'manimgl' && matrix.os == 'macos-latest'
run: pip3 install --user manimgl
- name: Install manimgl on Ubuntu and Windows
if: matrix.manim == 'manimgl' && matrix.os != 'macos-latest'
run: python -m pip install --user manimgl
- name: Install manim-slides on MacOS
if: matrix.os == 'macos-latest'
run: pip3 install --user .
- name: Install manim-slides on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: xvfb-run -a -s "-screen 0 1400x900x24" python -m pip install --user .
- name: Install manim-slides on Windows
if: matrix.os == 'windows-latest'
run: pip3 install -e .
- name: Build slides with manim
if: matrix.manim == 'manim'
run: python -m manim -ql example.py Example ThreeDExample
- name: Build slides with manimgl on Ubuntu
if: matrix.manim == 'manimgl' && matrix.os == 'ubuntu-latest'
run: xvfb-run -a -s "-screen 0 1400x900x24" manim-render -l example.py Example ThreeDExample
- name: Build slides with manimgl on MacOS or Windows
if: matrix.manim == 'manimgl' && (matrix.os == 'macos-latest' || matrix.os == 'windows-latest')
run: manimgl -l example.py Example ThreeDExample
- name: Test slides on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: xvfb-run -a -s "-screen 0 1400x900x24" manim-slides Example ThreeDExample --skip-all
- name: Test slides on MacOS or Windows
if: matrix.os == 'macos-latest' || matrix.os == 'windows-latest'
run: manim-slides Example ThreeDExample --skip-all

View File

@ -1,6 +1,15 @@
# If you want to use manimgl, uncomment change
# manim to manimlib
from manimlib import *
import sys
if "manim" in sys.modules:
from manim import *
MANIMGL = False
elif "manimlib" in sys.modules:
from manimlib import *
MANIMGL = True
else:
raise ImportError("This script must be run with either `manim` or `manimgl`")
from manim_slides import Slide, ThreeDSlide
@ -31,37 +40,88 @@ class Example(Slide):
self.play(dot.animate.move_to(ORIGIN))
class ThreeDExample(ThreeDSlide):
def construct(self):
axes = ThreeDAxes()
circle = Circle(radius=3, color=BLUE)
dot = Dot(color=RED)
# For ThreeDExample, things are different
self.add(axes)
if not MANIMGL:
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
class ThreeDExample(ThreeDSlide):
def construct(self):
axes = ThreeDAxes()
circle = Circle(radius=3, color=BLUE)
dot = Dot(color=RED)
self.play(GrowFromCenter(circle))
self.begin_ambient_camera_rotation(rate=75 * DEGREES / 4)
self.add(axes)
self.pause()
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=4, rate_func=linear)
self.end_loop()
self.play(GrowFromCenter(circle))
self.begin_ambient_camera_rotation(rate=75 * DEGREES / 4)
self.stop_ambient_camera_rotation()
self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES)
self.pause()
self.play(dot.animate.move_to(ORIGIN))
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=4, rate_func=linear)
self.end_loop()
self.play(dot.animate.move_to(RIGHT * 3))
self.pause()
self.stop_ambient_camera_rotation()
self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES)
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
self.play(dot.animate.move_to(ORIGIN))
self.pause()
# Each slide MUST end with an animation (a self.wait is considered an animation)
self.play(dot.animate.move_to(ORIGIN))
self.play(dot.animate.move_to(RIGHT * 3))
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
# Each slide MUST end with an animation (a self.wait is considered an animation)
self.play(dot.animate.move_to(ORIGIN))
else:
# WARNING: 3b1b's manim change how ThreeDScene work,
# this is why things have to be managed differently.
class ThreeDExample(Slide):
CONFIG = {
"camera_class": ThreeDCamera,
}
def construct(self):
axes = ThreeDAxes()
circle = Circle(radius=3, color=BLUE)
dot = Dot(color=RED)
self.add(axes)
frame = self.camera.frame
frame.set_euler_angles(
theta=30 * DEGREES,
phi=75 * DEGREES,
gamma=0,
)
self.play(GrowFromCenter(circle))
updater = lambda m, dt: m.increment_theta((75 * DEGREES / 4) * dt)
frame.add_updater(updater)
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=4, rate_func=linear)
self.end_loop()
frame.remove_updater(updater)
self.play(frame.animate.set_theta(30 * DEGREES))
self.play(dot.animate.move_to(ORIGIN))
self.pause()
self.play(dot.animate.move_to(RIGHT * 3))
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
# Each slide MUST end with an animation (a self.wait is considered an animation)
self.play(dot.animate.move_to(ORIGIN))

View File

@ -1 +1 @@
__version__ = "3.2.2"
__version__ = "3.2.3"

View File

@ -174,10 +174,18 @@ class Presentation:
class Display:
def __init__(self, presentations, config, start_paused=False, fullscreen=False):
def __init__(
self,
presentations,
config,
start_paused=False,
fullscreen=False,
skip_all=False,
):
self.presentations = presentations
self.start_paused = start_paused
self.config = config
self.skip_all = skip_all
self.state = State.PLAYING
self.lastframe = None
@ -206,7 +214,7 @@ class Display:
scale = min(scale_height, scale_width)
return cv2.resize(frame, (int(scale * frame_height, scale * frame_width)))
return cv2.resize(frame, (int(scale * frame_height), int(scale * frame_width)))
@property
def current_presentation(self):
@ -293,7 +301,9 @@ class Display:
):
self.current_presentation.next()
self.state = State.PLAYING
elif self.state == State.PLAYING and self.config.CONTINUE.match(key):
elif (
self.state == State.PLAYING and self.config.CONTINUE.match(key)
) or self.skip_all:
self.current_presentation.next()
elif self.config.BACK.match(key):
if self.current_presentation.current_slide_i == 0:
@ -356,8 +366,15 @@ def _list_scenes(folder):
is_flag=True,
help="Show the next animation first frame as last frame (hack).",
)
@click.option(
"--skip-all",
is_flag=True,
help="Skip all slides, useful the test if slides are working.",
)
@click.help_option("-h", "--help")
def present(scenes, config_path, folder, start_paused, fullscreen, last_frame_next):
def present(
scenes, config_path, folder, start_paused, fullscreen, last_frame_next, skip_all
):
"""Present the different scenes."""
if len(scenes) == 0:
@ -411,6 +428,10 @@ def present(scenes, config_path, folder, start_paused, fullscreen, last_frame_ne
config = Config()
display = Display(
presentations, config=config, start_paused=start_paused, fullscreen=fullscreen
presentations,
config=config,
start_paused=start_paused,
fullscreen=fullscreen,
skip_all=skip_all,
)
display.run()

View File

@ -32,7 +32,7 @@ setuptools.setup(
"numpy>=1.19.3",
"pydantic>=1.9.1",
"opencv-python>=4.6",
"tqdm",
"tqdm>=4.62.3",
],
classifiers=[
"Programming Language :: Python :: 3",