Compare commits

..

209 Commits

Author SHA1 Message Date
5734d0dc18 chore(gh-pages): remove hidden files 2024-01-31 14:13:22 +01:00
b5620650ba chore(gh-pages): remove everything 2024-01-31 14:11:18 +01:00
b17fd5409f chore(docs): use RTD (#365)
* chore(docs): use RTD

* chore(ci): remove pages deployment
2024-01-31 13:36:53 +01:00
186badba03 chore(docs): add Binder badge 2024-01-29 09:12:55 +01:00
39816d4994 chore(docs): update changelog 2024-01-26 18:21:38 +01:00
9cb1dae990 chore(version): bump to 5.1.0 2024-01-26 18:19:09 +01:00
9e4c1d76ee fix(ci): upload from ghcr 2024-01-26 17:04:18 +01:00
0316adf69e fix(ci): was-it just a typo? 2024-01-26 16:13:09 +01:00
fd9b06b955 chore(version): bump 5.1.0-rc3 to 5.1.0-rc4 2024-01-26 15:14:25 +01:00
16f740d2ad chore(deps): make Qt backend optional (#350)
* chore(deps): make Qt backend optional

TODO:
- [ ] Add relevant entry in CHANGELOG
- [ ] Update install documentation
- [ ] Make sure `manim-slides convert` can run without any Qt backend
- [ ] Make sure test suite works (partially) without any Qt backend
- [ ] Make sure we can import `manim_slides` without any Qt backend

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

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

* chore(deps): some fixes but wip

* chore(docs): update

* chore(deps): support PyQt6

* chore(deps): make Qt backend optional

TODO:
- [ ] Add relevant entry in CHANGELOG
- [ ] Update install documentation
- [ ] Make sure `manim-slides convert` can run without any Qt backend
- [ ] Make sure test suite works (partially) without any Qt backend
- [ ] Make sure we can import `manim_slides` without any Qt backend

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

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

* chore(deps): some fixes but wip

* chore(docs): update

* chore(deps): support PyQt6

* fix(deps): ci and docs

* fix(lib): missing package

* chore(ci): does it work?

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

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

* chore(test): skip failing

* chore(docs): update

* chore(docs): update

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

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

* fix(docs): typo

* fix(test): quit instead of shutdown

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-26 15:08:23 +01:00
f260d0d310 chore(deps): bump ssciwr/setup-mesa-dist-win from 1 to 2 (#361)
Bumps [ssciwr/setup-mesa-dist-win](https://github.com/ssciwr/setup-mesa-dist-win) from 1 to 2.
- [Release notes](https://github.com/ssciwr/setup-mesa-dist-win/releases)
- [Commits](https://github.com/ssciwr/setup-mesa-dist-win/compare/v1...v2)

---
updated-dependencies:
- dependency-name: ssciwr/setup-mesa-dist-win
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-26 12:00:39 +01:00
39ff80ed1e chore(deps): bump pdm-project/setup-pdm from 3 to 4 (#360)
Bumps [pdm-project/setup-pdm](https://github.com/pdm-project/setup-pdm) from 3 to 4.
- [Release notes](https://github.com/pdm-project/setup-pdm/releases)
- [Commits](https://github.com/pdm-project/setup-pdm/compare/v3...v4)

---
updated-dependencies:
- dependency-name: pdm-project/setup-pdm
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-26 12:00:25 +01:00
b84a22d0f9 [pre-commit.ci] pre-commit autoupdate (#358)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.13 → v0.1.14](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.13...v0.1.14)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-23 11:07:55 +01:00
7ba47728ff chore(docs): document HTML custom templates (#357)
* chore(docs): document HTML custom templates

Shows an example of custom template.

TODO:
- [ ] finish documentating;
- [ ] add possibility to pass `-cargs` to Manim Slides' `convert` method when calling the Sphinx extension.

Closes #356

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

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

* chore(docs): document changes and fix

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-23 11:07:36 +01:00
02a8173ed1 fix(lib): reversed video quality 2024-01-19 13:27:40 +01:00
07dff32be3 chore(ci): rename 2024-01-18 23:36:02 +01:00
e60edcc960 fix(ci): remove duplicate info 2024-01-18 23:34:07 +01:00
c1d2dc26b2 fix(ci): avoid dynamic if does not work 2024-01-18 23:33:00 +01:00
0db4a8c260 fix(ci): update 2024-01-18 23:24:49 +01:00
cb4f6f552c fix(docs): typos 2024-01-18 22:20:55 +01:00
9cd50e73b2 chore(docs): nicer placement 2024-01-18 22:15:04 +01:00
cea3d0b0c3 chore(version): bump 5.1.0-rc2 to 5.1.0-rc3 2024-01-18 22:07:43 +01:00
75126d8bab fix(docs): typo 2024-01-18 22:04:10 +01:00
be227bbdea chore(deps): use PDM instead of Poetry (#354)
* chore(deps): use PDM instead of Poetry

* chore(git): move to top

* chore(lint): fixes

* fix(pdm): dynamic version did not work

* chore(ci): fix syntax for Windows

* fix(ci): typo

* wip(docs): updates

* chore(docs): add changelog entry

* chore(docs): admonitions

* chore(docs): update to use manim-slides render

* chore(docs): make it better
2024-01-18 22:02:53 +01:00
62560ea41f chore(ci): create Docker image (#355)
* chore(ci): create Docker image

* fix(ci): run only if tag is pushed

* chore(docs): add changelog entry
2024-01-18 19:57:35 +01:00
4b8f90c1fa chore(LICENSE): update date 2024-01-18 19:04:45 +01:00
8b1c45b84e [pre-commit.ci] pre-commit autoupdate (#352)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.11 → v0.1.13](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.11...v0.1.13)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-18 12:02:58 +01:00
34cc66d8be chore(deps): bump actions/cache from 3 to 4 (#353)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-18 11:50:35 +01:00
57e11a0ea7 chore(deps): bump jinja2 from 3.1.2 to 3.1.3 (#349)
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.3)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 16:32:36 +01:00
de342b32bb [pre-commit.ci] pre-commit autoupdate (#347)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.9 → v0.1.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.9...v0.1.11)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-08 23:06:49 +01:00
6bd431d748 chore(lib): remove useless var 2024-01-04 13:06:56 +01:00
2e996c03a7 chore(deps): bump actions/deploy-pages from 3 to 4 (#342)
Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 3 to 4.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 13:06:13 +01:00
d9715ccb96 chore(deps): bump actions/upload-pages-artifact from 2 to 3 (#343)
Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 13:06:06 +01:00
e3b3dd677f chore(deps): bump github/codeql-action from 2 to 3 (#338)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 13:05:59 +01:00
db91de1412 [pre-commit.ci] pre-commit autoupdate (#337)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.11.0 → v2.12.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.11.0...v2.12.0)
- [github.com/astral-sh/ruff-pre-commit: v0.1.6 → v0.1.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.6...v0.1.9)
- [github.com/pre-commit/mirrors-mypy: v1.7.1 → v1.8.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.7.1...v1.8.0)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-04 13:05:43 +01:00
bf67a7b695 chore(deps): bump actions/upload-artifact from 3 to 4 (#339)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 11:48:24 +01:00
ea2d352fc1 chore(lib): do not include reversed files in HTML assets (#336)
* chore(lib): do not include reversed files in HTML assets

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-11 13:58:39 +01:00
74ddefe519 chore(deps): remove subprocess calls to FFMPEG with av (#335)
* chore(deps): remove subprocess calls to FFMPEG with `av`

Linked to the progess made in https://github.com/ManimCommunity/manim/pull/3501.

The following PR aims at reducing subprocess calls for security and speed reasons. Also, with https://github.com/ManimCommunity/manim/pull/3501 is merged, FFMPEG should not be needed anymore as it is part of `PyAv`.

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

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

* fix(lib): oops forgot to commit those changes

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

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

* chore(lib): clear assets and clean code

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

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

* chore(doc): document changes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-11 13:53:58 +01:00
20b7ef4110 chore(deps): bump actions/deploy-pages from 2 to 3 (#329)
* chore(deps): bump actions/deploy-pages from 2 to 3

Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 2 to 3.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

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

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-11 13:37:07 +01:00
19a31a9136 chore(deps): bump actions/configure-pages from 3 to 4 (#330)
* chore(deps): bump actions/configure-pages from 3 to 4

Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 3 to 4.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](https://github.com/actions/configure-pages/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

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

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-11 13:36:55 +01:00
d2925340aa chore(deps): bump actions/setup-python from 4 to 5 (#333)
* chore(deps): bump actions/setup-python from 4 to 5

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

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

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-07 08:36:32 +01:00
afeaa0d793 chore(version): bump 5.1.0-rc1 to 5.1.0-rc2 2023-12-05 13:29:43 +01:00
af3c4971ae feat(lib): add return_animation option (#331)
* feat(lib): add `return_animation` option

Allow to return animation instead of playing it.

* fix(lib): docs issue

* fix(ci): build with Python 3.10
2023-12-05 13:29:16 +01:00
b3ed127e31 chore(repo): delete unwanted file 2023-11-28 15:56:52 +01:00
fc200f22f5 chore(version): bump 5.0.0 to 5.1.0-rc1
chore(version): bump 5.0.0-rc1 to 5.1.0

chore(version): bump 5.1.0 to 5.1.0-rc1
2023-11-28 15:21:03 +01:00
050ee0ae78 feat(lib): enhance notes support (#324)
* feat(lib): enhance notes support

TODO: fix keyboard inputs and window order with `present`.

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

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

* chore(lint): allow too complex

* wip: presenter mode

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

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

* feat(cli): add presenter view

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-28 15:15:56 +01:00
a9b8081167 [pre-commit.ci] pre-commit autoupdate (#326)
updates:
- [github.com/pre-commit/mirrors-mypy: v1.7.0 → v1.7.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.7.0...v1.7.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-28 09:48:44 +01:00
dc58d498a8 feat(cli): automatically detect conversion format from DEST (#325)
* feat(cli): automatically detect conversion format from DEST

As titled

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

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

* fix(cli): fix and add tests

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

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

* fix(ci): ?

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-27 16:13:40 +01:00
f898dd3054 feat(lib): add support for presenter notes (#322)
* feat(lib): add support for presenter notes

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

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

* fix(test): typo

* Update test_slide.py

* Update convert.py

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-23 18:20:10 +01:00
b09a000c17 chore(lib): simplify how to add config options (#321)
* chore(lib): simplify how to add config options

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

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

* chore(lint): some fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-23 15:38:49 +01:00
eb8efa8e3d feat(lib): add playback rate config options (#320)
* feat(lib): add playback rate config options

Basic playback rate config options, closes #309

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-23 12:26:25 +01:00
1f0c94dc5c fix(cli): typo 2023-11-23 00:10:56 +01:00
2771aac4d0 chore(cli): reduce timeout for version check 2023-11-22 18:28:57 +01:00
ce799aeded feat(cli): add render command as alias to manim render (#317)
* feat(cli): add render command as alias to `manim render`

* feat(cli): add render command as alias to `manim render`

* chore(test): add test

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

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

* chore(lib): simplify how ManimGL rendering is called

* chore(lib): test

* chore(ci): try identify error

* wip

* chore(test): add result output

* try: checkout

* Revert "try: checkout"

This reverts commit 60985f0b612ca0c6bff9726ebcccf07b1b1c4832.

* fix(deps): don't update lock

* chore(lib): simplify code and improve usage

* chore(cli): better cli

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

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

* fix: does this fix?

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-22 18:26:44 +01:00
891273b2fc [pre-commit.ci] pre-commit autoupdate (#318)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.5 → v0.1.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.5...v0.1.6)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-21 17:42:41 +01:00
2b25b6a89d chore(docs): warn users about #314 (#319)
* chore(docs): warn users about #314

Closes #316

* chore(lint): apply suggested changes
2023-11-21 17:37:30 +01:00
fc594533e9 [pre-commit.ci] pre-commit autoupdate (#310)
updates:
- [github.com/psf/black: 23.10.1 → 23.11.0](https://github.com/psf/black/compare/23.10.1...23.11.0)
- [github.com/astral-sh/ruff-pre-commit: v0.1.4 → v0.1.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.4...v0.1.5)
- [github.com/pre-commit/mirrors-mypy: v1.6.1 → v1.7.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.1...v1.7.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-19 10:42:18 +01:00
422102524f fix(lib): remove dummy content 2023-11-16 13:07:29 +01:00
739cbcee0a feat(cli): added --hide-info-window option (#313)
* feat(cli): added `--hide-info-window` option

This was suggested by Discord use #dung_14424 on the Manim Discord.

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-16 12:51:59 +01:00
3b3e3109a3 [pre-commit.ci] pre-commit autoupdate (#306)
updates:
- [github.com/psf/black: 23.10.0 → 23.10.1](https://github.com/psf/black/compare/23.10.0...23.10.1)
- [github.com/astral-sh/ruff-pre-commit: v0.1.1 → v0.1.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.1...v0.1.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-11-12 11:01:36 +01:00
8921c3b8f9 chore(README): fix relative link for Windows image 2023-11-01 10:06:00 +01:00
5eb23dc5c1 chore(version): update changelog version 2023-10-30 10:54:14 +01:00
a890832a4d chore(version): bump 5.0.0-rc3 to 5.0.0 2023-10-30 10:52:53 +01:00
106c7d4c06 feat(cli): add next-terminates-loop CLI option (#299)
* feat(cli): add `next-terminates-loop` CLI option

Closes #254

* chore(lib): fix `--next-terminates-loop`

* chore(CHANGELOG): document changes
2023-10-30 10:50:26 +01:00
6c52906037 feat(lib): add auto_next option (#304)
* feat(lib): add `auto_next` option

As suggested in #302, you can now automatically skip a slide. It works both with `present` and `convert --to=html`!

Closes #302

* chore(ci): add trigger on push on main
2023-10-30 10:12:59 +01:00
2853ed08e1 chore(tests): adding tests for Qt widgets (#300)
* chore(tests): adding tests for Qt widgets

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

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

* fix: reset WINDOW name

* chore(tests): addign tests

* chore: adding more tests

* fix how bin existence is checked

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

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

* fix: which takes str

* more tests!

* todo: fix

* change verbosity in tests

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-27 16:40:05 +02:00
760ceb8ce1 [pre-commit.ci] pre-commit autoupdate (#298)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/psf/black: 23.9.1 → 23.10.0](https://github.com/psf/black/compare/23.9.1...23.10.0)
- [github.com/astral-sh/ruff-pre-commit: v0.0.292 → v0.1.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.292...v0.1.1)
- [github.com/pre-commit/mirrors-mypy: v1.6.0 → v1.6.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.0...v1.6.1)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-23 22:59:52 +02:00
2fa0301935 Merge remote-tracking branch 'origin/main' into main 2023-10-23 17:39:01 +02:00
61b983db3a chore(version): bump 5.0.0-rc2 to 5.0.0-rc3 2023-10-23 17:38:49 +02:00
56b1ffe430 fix(deps): PySide6 player black screen (#297)
Fixes #293
2023-10-23 17:38:24 +02:00
541bf96945 feat(lib): add Slide.next_section method (#295)
* feat(lib): add `Slide.next_section` method

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-23 17:34:20 +02:00
626764146a chore(docs): add explicit targets 2023-10-20 09:26:08 +02:00
0322dae743 feat(lib): add loop option to next_slide and remove start/end_loop (#294)
* feat(lib): add `loop` option to `next_slide` and remove `start/end_loop`

* fix(docs): PR number
2023-10-19 15:37:54 +02:00
7928f6020c Merge branch 'color' into main 2023-10-19 14:32:37 +02:00
f3dfa782b0 fix(convert): ClassVar was ignored by Pydantic (#292)
* fix(convert): ClassVar was ignored by Pydantic

Using default factory function instead.

* update comments
2023-10-19 14:31:39 +02:00
e13ca7e0dc chore(lib): use pydantic color 2023-10-19 14:17:30 +02:00
6c9505b98a fix(lib): use optional instead of mutable defaults (#291)
* fix(lib): use optional instead of mutable defaults

* fix: add missing check for none
2023-10-19 11:52:14 +02:00
7b3a5c4824 fix(ci): OpenGL issue on Windows server (#290)
* fix(ci): OpenGL issue on Windows server

Attempt at fixing OpenGL issue on Windows server

* fix(ci): unmark xfail

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-19 11:39:16 +02:00
5daa94b823 chore(ci): enhance current lint rules (#289)
* chore(ci): enhance current lint rules

* run linter

* fix all warnings

* fix(convert): release VideoCapture

* fix(ci): properly close file

* better tests

* fix(ci): setup opengl

* Revert "fix(ci): setup opengl"

This reverts commit a33f53a1c04f909d7660f2b5221c763a9ef97d53.

* fix(ci): skipif Windows in workflows

* actually xfail
2023-10-18 19:24:14 +02:00
498e33ad8d chore(deps): bump urllib3 from 2.0.6 to 2.0.7 (#288)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.0.6...2.0.7)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 23:33:25 +02:00
860ab231b5 chore(tests): add tests for converter methods (#283)
* chore(tests): add tests for converter methods

* chore(tests): update ppt converter test

---------

Co-authored-by: Jérome Eertmans <jeertmans@icloud.com>
2023-10-17 22:33:01 +02:00
c075904a27 fix(ci): wrong logic 2023-10-17 16:58:59 +02:00
387d0f76b5 fix(convert): disallow empty list 2023-10-17 16:50:48 +02:00
1126a20785 fix(docs): remove return type 2023-10-17 16:22:56 +02:00
802f6406ae refactor(lib): change how manim API is imported (#285)
* refactor(lib): change how manim API is imported

* chore(lib): delete old files

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

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

* wip: moving all commands

* adding animations

* fix tests

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

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

* fix mypy

* fixes

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

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

* trying to fix docs

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

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

* wip: docs

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

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

* make it work

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

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

* wip test

* tests are working

* improving docs

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

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

* fix index

* docs: nicer shift

* docs: nicer quickstart example

* fix tests

* change tests

* move coverage to test workflow

* fix(tests): remove resolve

* strict resolve

* change local path test

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

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

* documented changes

* cleanup docs

* cleanup files

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

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

* fix(ci): set type

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-17 16:06:19 +02:00
685f871186 [pre-commit.ci] pre-commit autoupdate (#286)
updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.10.0 → v2.11.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.10.0...v2.11.0)
- [github.com/pre-commit/mirrors-mypy: v1.5.1 → v1.6.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.5.1...v1.6.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-17 12:52:17 +02:00
da14b5f24a [pre-commit.ci] pre-commit autoupdate (#284)
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-14 10:15:38 +02:00
18a9906ae5 chore(deps): bump urllib3 from 2.0.4 to 2.0.6 (#280)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.4 to 2.0.6.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.0.4...2.0.6)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-05 10:04:34 +02:00
a0ee723c89 [pre-commit.ci] pre-commit autoupdate (#281)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.291 → v0.0.292](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.291...v0.0.292)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-05 10:04:22 +02:00
2b7bd0a68d Add github template to sharing page (#279)
* chore(docs): add github template to sharing page

* chore(docs): update according to style requirements
2023-10-05 10:03:55 +02:00
497e4e964f fix(docs): changelog link 2023-10-01 21:43:09 +02:00
86fc774a3d [pre-commit.ci] pre-commit autoupdate (#274)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.290 → v0.0.291](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.290...v0.0.291)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-27 18:46:02 +02:00
ce14c79230 [pre-commit.ci] pre-commit autoupdate (#273)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.288 → v0.0.290](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.288...v0.0.290)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-19 08:44:45 +02:00
6272d3f7ec fix(cli/convert): ensure dest path can be written (#262)
Fixes the issue that non-existing parent(s) in the dest path would raise an error.
2023-09-15 11:29:30 +02:00
bbe8b96030 chore(version): bump 5.0.0-rc1 to 5.0.0-rc2 2023-09-14 11:31:13 +02:00
1bc8423381 chore(deps): bump RevealJS' default version to 4.6.1 (#272)
Add 3 new themes: dracula, dark-contrast and white-contrast.
2023-09-14 11:30:13 +02:00
67147442f3 chore(convert): use Jinja2 for templating (#271)
* chore(convert): use Jinja2 for templating

Use Jinja2 templating for more customizable rendering

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

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

* fix(deps): jinja2 is no more optional

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-14 11:21:20 +02:00
859d48ad2e [pre-commit.ci] pre-commit autoupdate (#270)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1)
- [github.com/astral-sh/ruff-pre-commit: v0.0.287 → v0.0.288](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.287...v0.0.288)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-12 16:03:46 +02:00
9a23296fa2 fix(docs): change example to not use LaTeX 2023-09-06 17:54:17 +02:00
0f5b374bce fix(docs): remove TeX deps in examples 2023-09-06 15:26:54 +02:00
2dc4c1ab99 chore(docs): update docs about data URI 2023-09-06 15:23:54 +02:00
f2ee29ad58 chore(docs): render subclass example 2023-09-06 15:12:29 +02:00
d127af9dd2 fix(docs): typo in rst directive 2023-09-06 10:45:38 +02:00
05ebf40543 chore(deps): bump actions/checkout from 3 to 4 (#264)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 19:22:43 +02:00
9cc7957e35 [pre-commit.ci] pre-commit autoupdate (#263)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.286 → v0.0.287](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.286...v0.0.287)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-05 19:22:24 +02:00
b72b7bc256 fix(docs): 404 file not found fixed 2023-09-05 19:21:58 +02:00
4a1b8aea87 fix(docs): casing 2023-08-29 23:22:46 +02:00
c2b12d16eb fix(docs): syntax hl 2023-08-29 16:36:11 +02:00
bb5b294f40 feat(lib): Sphinx directive can now read files (#261)
* feat(lib): Sphinx directive can now read files

You can optionally read a file instead of the Sphinx directive's content

* fix(lib): rst syntax and docs

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-29 16:23:54 +02:00
9a3a343231 [pre-commit.ci] pre-commit autoupdate (#260)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.285 → v0.0.286](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.285...v0.0.286)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-29 14:50:56 +02:00
0f07d36f52 fix(deps): patch color for future manim versions (#255) 2023-08-28 17:09:19 +02:00
806b7d00f6 fix(lib): correctly format enums on Python>=3.11 (#257)
Closes #256

fix(tests): update tests and fix


chore(lib): simplify fix and more tests


chore(docs): document patch
2023-08-24 13:22:04 +02:00
3d9522cbb0 chore(deps): remove notebook dependencies (#248)
* chore(deps): remove notebook dependencies

Unused optional dependency.

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-22 11:25:33 +02:00
28c5336b83 [pre-commit.ci] pre-commit autoupdate (#247)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.284 → v0.0.285](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.284...v0.0.285)
- [github.com/pre-commit/mirrors-mypy: v1.5.0 → v1.5.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.5.0...v1.5.1)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-22 11:06:37 +02:00
48614105bd chore(version): bump 4.16.0 to 5.0.0-rc1 2023-08-21 22:15:15 +02:00
933afdd465 fix 2023-08-21 22:08:34 +02:00
599f9f22ae chore(ci): update bump config
fix(ci): regex


fix(ci): bump regex


fix


fix
2023-08-21 22:07:39 +02:00
5490a0a5ef chore(docs): add changelog to online docs 2023-08-21 21:34:37 +02:00
c875363b40 [ImgBot] Optimize images (#246)
*Total -- 5,933.58kb -> 1,375.26kb (76.82%)

/paper/docs.png -- 4,390.51kb -> 157.54kb (96.41%)
/static/example.gif -- 669.78kb -> 484.93kb (27.6%)
/static/logo_dark_github.png -- 112.68kb -> 86.31kb (23.4%)
/static/logo_dark_docs.png -- 111.55kb -> 86.00kb (22.9%)
/static/logo.png -- 109.63kb -> 89.99kb (17.91%)
/static/windows_quality_fix.png -- 34.61kb -> 29.19kb (15.65%)
/static/docs.png -- 209.36kb -> 177.73kb (15.11%)
/static/logo_light_transparent.png -- 116.05kb -> 102.36kb (11.79%)
/static/icon.png -- 2.03kb -> 1.79kb (11.61%)
/static/logo_dark_transparent.png -- 123.63kb -> 109.45kb (11.46%)
/static/wizard_light.png -- 26.28kb -> 24.23kb (7.8%)
/static/wizard_dark.png -- 27.48kb -> 25.72kb (6.43%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2023-08-21 20:53:39 +02:00
bd9bf06876 chore(cli): remove unused PERF verbosity level (#245)
* chore(cli): remove unused PERF verbosity level

As titled.

* fix(tests): remove perf in tests
2023-08-21 18:00:56 +02:00
4d76f2ccc1 chore(deps): bump tornado from 6.3.2 to 6.3.3 (#244)
Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.3.2 to 6.3.3.
- [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst)
- [Commits](https://github.com/tornadoweb/tornado/compare/v6.3.2...v6.3.3)

---
updated-dependencies:
- dependency-name: tornado
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-21 17:10:29 +02:00
8cf05ea44d chore(docs): correctly quote code 2023-08-21 17:10:13 +02:00
638616c94f feat(cli): rewrite presentation player (#243)
* wip: rewrite player

* wip(cli): new player

* wip(player): allow to close

* Auto stash before merge of "rewrite-player" and "origin/rewrite-player"

* feat(cli): new player

* chore(docs): document changes

* feat(cli): add info window
2023-08-21 16:50:03 +02:00
b321161717 chore(lib/cli): one video per slide (#242)
* chore(lib/cli): one video per slide

As titled, this PR changes how Manim Slides used to work by only storing one video file per slide.

Previously, a slide would store all animations that occur during the given slide. Up to now, the only "advantage" of this was that it would allow the user to know which animation is played.
But, at the cost of a very complex logic in present, just especially for reversed slides.

On top of top, all converter actually need to concatenate the animations from each slide into one, so it is now performed at rendering time.

To migrate from previous Manim Slides versions, the best is the render the slides again, using `manim render` or `manimgl render`.

Currently, it is not possible to start at a given animation anymore. However, if wanted, I may re-implement this, but this would require to change the config file again.

* fix(ci): trying to fix tests

* chore(test): renaming files

* chore(docs): remove old line from changelog

* fix(docs): typo

* fix(ci): manimgl and smarter comparison

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-20 19:40:39 +02:00
7363281ff0 [pre-commit.ci] pre-commit autoupdate (#241)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.282 → v0.0.284](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.282...v0.0.284)
- [github.com/pre-commit/mirrors-mypy: v1.4.1 → v1.5.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.4.1...v1.5.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-15 09:50:02 +02:00
d056d8d8b1 chore(version): bump 4.15.0 to 4.16.0 2023-08-08 14:45:03 +02:00
c95929dc7d fix(ci): version bump 2023-08-08 14:44:59 +02:00
e08edb6fe1 chore(docs): make 2nd example more different 2023-08-08 14:30:43 +02:00
efc3017df8 chore(paper): add paper's doi, update badges and add CFF 2023-08-08 14:13:29 +02:00
788727ea22 Merge branch 'optional' into main 2023-08-08 10:47:37 +02:00
0bb0285b18 fix(docs): typo in magics name 2023-08-08 10:46:44 +02:00
ce878bece2 [pre-commit.ci] pre-commit autoupdate (#239)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.281 → v0.0.282](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.281...v0.0.282)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-08 09:47:39 +02:00
1275e9119f chore(deps): make all groups optional (#238)
* chore(deps): make all groups optional

* chore(deps): update lock file

* chore(ci): run apt-get update
2023-08-07 18:25:06 +02:00
5555ac2e54 chore(ci): run apt-get update 2023-08-07 18:14:42 +02:00
838de83c75 chore(deps): update lock file 2023-08-07 18:07:22 +02:00
f1f7146c7e chore(deps): make all groups optional 2023-08-07 18:06:12 +02:00
fb02764bb7 feat(lib): add Jupyter magic (#237)
* feat(lib): add Jupyter magic

And also use the same logger level as manim (by default)

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

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

* fix(lib): remove deleted module

* chore(lib): fix typing issues

* chore(docs): document magic

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

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

* fix(ci): install kernel

* fix(ci): spawning is not necessary (and fails)

* chore(ci): add ipykernel

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-07 17:47:03 +02:00
f6f2e4090f fix(lib): fix import * (typo in name) 2023-08-07 10:11:16 +02:00
146a2f7839 chore(paper): fix brackets
As proposed by @labarba
2023-08-06 21:38:08 +02:00
d282766f2d feat(convert): support base64 encoded videos (#236)
* feat(convert): support base64 encoded videos

Thanks to @t-fritsch, Manim Slides can now convert to a fully self-contained HTML presentation using base64 encoded videos!

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

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

* chore(lib): explicit decode type

* feat(lib): auto detect mime type

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-06 19:06:43 +02:00
dec2f5e724 chore(docs): actually apply my own recomm. in example :-) 2023-08-04 16:49:37 +02:00
4d44166677 chore(version): bump 4.14.0 to 4.15.0 2023-08-04 16:17:50 +02:00
455f104a11 fix(present): finish up state machine (#234) 2023-08-04 16:17:21 +02:00
0f9048a27b fix(present): finish up state machine 2023-08-04 16:03:52 +02:00
9e1e0f2367 fix(lib): correctly caching and simplified structure (#233) 2023-08-04 13:37:27 +02:00
097ae8ffdd feat(present): fix presentation size and add screen option (#232)
* feat(present): fix presentation size and add screen option

This kinda fixes the issue of weird resizes between two presentations

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

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

* fix(ci): typing

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-04 13:33:21 +02:00
aace5dea11 fix(lib): correctly caching and simplified structure 2023-08-04 13:32:51 +02:00
738c54f9a6 chore(ci): ignore type 2023-08-04 11:15:38 +02:00
f01f811639 chore(present): inform about SIGINT 2023-08-04 11:14:24 +02:00
94265f6842 chore(present): warn about old configuration file 2023-08-04 10:46:35 +02:00
6ed76ffd01 fix(lib): correct key attribute 2023-08-04 10:45:19 +02:00
71df62d79b chore(docs): line length too long 2023-08-04 09:55:01 +02:00
fc36909688 chore(tests): zoom example 2023-08-04 09:54:42 +02:00
580da4a885 chore(docs): add some more indications 2023-08-02 16:59:02 +02:00
0de877e43a fix(docs): typo in RST 2023-08-02 16:48:59 +02:00
7313e3e0d4 feat(lib): add zoom animation (#230)
* feat(lib): add zoom animation

* chore(lib): fix zoom animation
2023-08-02 13:47:38 +02:00
1e967894db fix(lib): check if reversed file exist (#231)
This fixes a bug that would block the process forever because FFMPEG was asking if it could overwrite or not.
2023-08-02 12:54:00 +02:00
98fa5349d3 [pre-commit.ci] pre-commit autoupdate (#229)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.280 → v0.0.281](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.280...v0.0.281)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-01 20:56:40 +02:00
0e3ed3f9eb chore(deps): bump certifi from 2023.5.7 to 2023.7.22 (#228)
Bumps [certifi](https://github.com/certifi/python-certifi) from 2023.5.7 to 2023.7.22.
- [Commits](https://github.com/certifi/python-certifi/compare/2023.05.07...2023.07.22)

---
updated-dependencies:
- dependency-name: certifi
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-27 09:33:12 +02:00
a45242236d chore(docs): add sphinx extension link 2023-07-25 14:39:47 +02:00
66451473b8 [pre-commit.ci] pre-commit autoupdate (#226)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.278 → v0.0.280](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.278...v0.0.280)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-25 10:29:38 +02:00
72152bd625 docs: fixed typo (#227)
Change link titled "HTML Presenetation" (typo) to "HTML Presentation".
2023-07-25 10:29:21 +02:00
88bffe0f0b chore(lib): remove all os.path in favor to pathlib (#225)
* chore(lib): remove all os.path in favor to pathlib

* fix(lib): str to path
2023-07-24 15:53:30 +02:00
a7719dbb8b feat(lib): change config file from json to toml (#224)
This PR introduces a **BREAKING CHANGE**: the general config file is now written in the TOML format. Keys are also placed under a shared subsection. Previous config files will be ignore.

Migration from the previous format can be easily performed with `manim-slides init` and copy/pasting the key codes if necessary.
2023-07-24 14:46:15 +02:00
529a6c534f fix(lib/cli): relative paths, empty slides, and tests (#223)
* fix(lib/cli): relative paths, empty slides, and tests

This fixes two issues:

1. Empty slides are now reported as error, to prevent indexing error;
2. Changing the folder path will now produce an absolute path to slides, which was not the case before and would lead to a "file does not exist error".

A few tests were also added to cover those

* fix(lib): fix from_file, remove useless field, and more

* chore(tests): remove print

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-24 13:58:54 +02:00
2b6240c4d3 chore(tests): test commons and defaults (#222)
Add new tests to improve overall coverage
2023-07-24 11:28:40 +02:00
d98d41aaa8 fix(lib/cli): fix validation error (#221) 2023-07-24 10:38:35 +02:00
d892a4e77d chore(docs): add fadeout 2023-07-20 17:36:55 +02:00
8069ab5405 chore(docs): improve example animation 2023-07-20 17:35:36 +02:00
f9e22fe63c chore(tests): improve test coverage (#220)
* chore(tests): improve test coverage

* chore(ci): fix display connection for manimgl

* chore(ci): same but for code coverage
2023-07-20 16:17:51 +02:00
b195b823ba chore(docs): improve directive's documentation 2023-07-20 13:59:28 +02:00
fc8717fa9c chore(docs): select docs members 2023-07-20 13:48:54 +02:00
dbbd6813ec feat(lib): add canvas and features (#219)
* feat(lib): add canvas and features

Add canvas to slide

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-20 13:38:18 +02:00
a10902eaaa feat(lib): add wait-time-between-slides attribute (#218)
Add a new attribute that will allow to automatically call `self.wait(...)` between two slides, to fix graphical issues.
2023-07-20 12:02:59 +02:00
f4c1c34994 feat(lib): improve wipe animation (#217)
* feat(lib): improve wipe animation

Improve wipe transition by using FadeIn and FadeOut. The also allows to support introducers and removers.

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-20 11:27:15 +02:00
540c7034c8 feat(lib/docs): add sphinx directive (#216)
This PR adds a new Sphinx directive, inspired by the Manim one. This directive is also used within the docs to display examples.
2023-07-19 17:11:58 +02:00
86aeeb861b feat(lib): add wip transition (#215) 2023-07-19 15:13:08 +02:00
979e2c549a [pre-commit.ci] pre-commit autoupdate (#212)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.9.0 → v2.10.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.9.0...v2.10.0)
- [github.com/psf/black: 23.3.0 → 23.7.0](https://github.com/psf/black/compare/23.3.0...23.7.0)
- [github.com/astral-sh/ruff-pre-commit: v0.0.276 → v0.0.278](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.276...v0.0.278)

* chore(ci): apply ruff's suggestion

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Jérome Eertmans <jeertmans@icloud.com>
2023-07-19 12:20:01 +02:00
4e4e29380b chore(lib): fix typo in warning message (#214) 2023-07-19 12:19:27 +02:00
caa4c48fe7 chore(deps): bump actions/upload-pages-artifact from 1 to 2 (#213)
Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 1 to 2.
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 12:02:31 +02:00
a353de270e chore(docs): fix typo 2023-07-07 17:18:55 +02:00
60f284e748 Update index.md (#210)
Small typo
2023-07-06 23:28:21 +02:00
501af3b658 chore(README): update token 2023-07-05 14:50:32 +02:00
f820819896 chore(ci): add coverage report 2023-07-05 14:46:42 +02:00
9279d2a22a chore(deps): bumping pydantic to V2 (#207)
* chore(deps): bumping pydantic to V2

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

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

* fix(lib): validators

* fix(ci): add tests and fixes

* fix(lib): add missing mode arg

* fix(lib): change function name

* chore(tests): add more tests and use pytest

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

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

* chore(deps): change test deps

* chore(ci): install manim deps

* fix(ci): move to right place

* fix(lib): add custom schema

* fix(lib): validators

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-05 14:35:58 +02:00
e1d5fb732c [pre-commit.ci] pre-commit autoupdate (#206)
updates:
- https://github.com/charliermarsh/ruff-pre-commithttps://github.com/astral-sh/ruff-pre-commit
- [github.com/astral-sh/ruff-pre-commit: v0.0.275 → v0.0.276](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.275...v0.0.276)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-05 10:05:55 +02:00
384af332d8 chore(deps): bump actions/checkout from 1 to 3 (#203)
Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-29 14:02:21 +02:00
c231f4d100 [pre-commit.ci] pre-commit autoupdate (#204)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.272 → v0.0.275](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.272...v0.0.275)
- [github.com/pre-commit/mirrors-mypy: v1.3.0 → v1.4.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.3.0...v1.4.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-06-29 14:02:12 +02:00
751eae74e9 chore(deps): bump actions/upload-artifact from 1 to 3 (#201)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 1 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 10:27:41 +02:00
97fe80caa2 chore(deps): bump actions/configure-pages from 2 to 3 (#200)
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 2 to 3.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](https://github.com/actions/configure-pages/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 10:27:29 +02:00
a7eea6fbea [pre-commit.ci] pre-commit autoupdate (#199)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.270 → v0.0.272](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.270...v0.0.272)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-06-13 10:27:16 +02:00
04e2f265f6 chore(deps): bump actions/deploy-pages from 1 to 2 (#202)
Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 1 to 2.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 10:27:02 +02:00
8096636cf1 chore(version): bump 4.13.2 to 4.14.0 2023-06-12 14:40:38 +02:00
c7e38bfb38 feat(convert): add to PDF conversion (#197)
* feat(convert): add to PDF conversion

Basic PDF conversion. It takes the last frame (by default) for each animation, and prints out a PDF page.

Closes #196

* chore(ci): remove experimental installer

* feat(convert): add to PDF conversion

Basic PDF conversion. It takes the last frame (by default) for each animation, and prints out a PDF page.

Closes #196

* feat(convert): add to PDF conversion

Basic PDF conversion. It takes the last frame (by default) for each animation, and prints out a PDF page.

Closes #196

* chore(deps): update lockfile
2023-06-12 14:28:20 +02:00
421cad3038 chore(deps): bump requests from 2.29.0 to 2.31.0 (#190)
Bumps [requests](https://github.com/psf/requests) from 2.29.0 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.29.0...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-12 13:53:31 +02:00
9edf23856c chore(deps): upgrading to qt6.5 (#198)
* chore(deps): upgrading to qt6.5

This PR proposes to update to PySide6.5.

On Ubuntu, you may face this problem (solution included): https://bugreports.qt.io/browse/PYSIDE-2306

* chore(ci): remove experimental installer
2023-06-12 13:46:15 +02:00
62236f5796 [pre-commit.ci] pre-commit autoupdate (#195)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.269 → v0.0.270](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.269...v0.0.270)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-06-09 11:33:48 +02:00
1e28d70c0e chore(README): add zenodo badge 2023-05-25 18:00:11 +02:00
6a96b3ab8c chore(version): bump 4.13.1 to 4.13.2 2023-05-25 17:47:50 +02:00
a1c041db80 chore(paper): add comparison section (#192)
Closes #188
2023-05-24 09:04:05 +02:00
4fd3452f95 chore(cli): fix and improve help messages (#191)
A very small PR to fix an error in an help message, and improve the verbosity one.
2023-05-23 10:42:23 +02:00
ff2be6851b [pre-commit.ci] pre-commit autoupdate (#189)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.267 → v0.0.269](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.267...v0.0.269)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-23 10:41:57 +02:00
95289ee7a5 [pre-commit.ci] pre-commit autoupdate (#187)
updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.8.0 → v2.9.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.8.0...v2.9.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.265 → v0.0.267](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.265...v0.0.267)
- [github.com/pre-commit/mirrors-mypy: v1.2.0 → v1.3.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.2.0...v1.3.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-18 17:19:31 +02:00
f1a026208a chore(docs): document scene subclassing (#186) 2023-05-11 19:43:32 +02:00
b3fd1d209e [pre-commit.ci] pre-commit autoupdate (#184)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.263 → v0.0.265](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.263...v0.0.265)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-09 10:27:21 +02:00
8c38db0989 chore(convert): add debug message 2023-05-08 19:15:31 +02:00
6da0c36c96 Revert "try(ci): remove cache for media"
This reverts commit 3b01efa6018dfb0902cfcd92e713ac8dd8f70e67.
2023-05-08 19:10:48 +02:00
3b01efa601 try(ci): remove cache for media 2023-05-08 18:39:14 +02:00
c9ef5e9a75 fix(pages): missing assets (#183)
* fix(pages): missing assets

This is a PR to try understanding why some assets are not present

* fix(ci): correct path

* fix(ci): fix path..

* chore(ci): add debug

* chore(ci): more and more debug
2023-05-08 17:43:58 +02:00
80 changed files with 4 additions and 8764 deletions

View File

@ -1,12 +0,0 @@
[bumpversion]
current_version = 4.13.1
commit = True
message = chore(version): bump {current_version} to {new_version}
[bumpversion:file:manim_slides/__version__.py]
search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"
[bumpversion:file:pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [jeertmans]

View File

@ -1,40 +0,0 @@
name: Bug
description: Report an issue to help improve the project.
labels: bug
title: '[BUG] <description>'
body:
- type: textarea
id: description
attributes:
label: Description
description: A brief description of the question or issue, also include what you tried and what didn't work
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: Which version of Manim Slides are you using? You can use `manim-slides --version` to get that information.
validations:
required: true
- type: textarea
id: platform
attributes:
label: Platform
description: What is your platform. Linux, macOS, or Windows?
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Please add screenshots if applicable
validations:
required: false
- type: textarea
id: extrainfo
attributes:
label: Additional information
description: Is there anything else we should know about this bug?
validations:
required: false

View File

@ -1,59 +0,0 @@
name: Documentation
description: Ask / Report an issue related to the documentation.
title: 'DOC: <description>'
labels: [bug, docs]
body:
- type: markdown
attributes:
value: >
**Thank you for wanting to report a problem with manim-slides docs!**
If the problem seems straightforward, feel free to submit a PR instead!
Verify first that your issue is not already reported on GitHub [Issues].
[Issues]:
https://github.com/jeertmans/manim-slides/issues
- type: textarea
attributes:
label: Describe the Issue
description: A clear and concise description of the issue you encountered.
validations:
required: true
- type: input
attributes:
label: Affected Page
description: Add a link to page with the problem.
validations:
required: true
- type: dropdown
attributes:
label: Issue Type
description: >
Please select the option in the drop-down.
<details>
<summary>
<em>Issue?</em>
</summary>
</details>
options:
- Documentation Enhancement
- Documentation Report
validations:
required: true
- type: textarea
attributes:
label: Recommended fix or suggestions
description: A clear and concise description of how you want to update it.
validations:
required: false

View File

@ -1,26 +0,0 @@
name: Feature Request
description: Have a new idea/feature? Please suggest!
labels: enhancement
title: '[FEATURE] <description>'
body:
- type: textarea
id: description
attributes:
label: Description
description: A brief description of the enhancement you propose, also include what you tried and what worked.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Please add screenshots if applicable
validations:
required: false
- type: textarea
id: extrainfo
attributes:
label: Additional information
description: Is there anything else we should know about this idea?
validations:
required: false

View File

@ -1,14 +0,0 @@
name: Question/Help/Support
description: Ask us about Manim Slides
title: 'Support: Ask us anything'
labels: [help, question]
body:
- type: textarea
attributes:
label: "Please explain the issue you're experiencing (with as much detail as possible):"
description: >
Please make sure to leave a reference to the document/code you're
referring to.
validations:
required: true

View File

@ -1,13 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
labels:
- dependencies

View File

@ -1,26 +0,0 @@
<!-- If your PR fixes an open issue, use `Closes #999` to link your PR with the issue. #999 stands for the issue number you are fixing -->
## Fixes Issue
<!-- Remove this section if not applicable -->
<!-- Example: Closes #31 -->
## Description
<!-- Describe all the proposed changes in your PR -->
## Check List (Check all the applicable boxes)
- [ ] I understand that my contributions needs to pass the checks.
- [ ] If I created new functions / methods, I documented them and add type hints.
- [ ] If I modified already existing code, I updated the documentation accordingly.
- [ ] The title of my pull request is a short description of the requested changes.
## Screenshots
<!-- Add all the screenshots which support your changes -->
## Note to reviewers
<!-- Add notes to reviewers if applicable -->

View File

@ -1,34 +0,0 @@
# From: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
name: Cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,72 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: CodeQL
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
- cron: 45 3 * * 2
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [python]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@ -1,33 +0,0 @@
# Simple workflow for deploying static content to GitHub Pages
name: Create JOSE Paper
on:
# Runs on pushes targeting the default branch
push:
paths:
- paper/*
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
paper:
runs-on: ubuntu-latest
name: Paper Draft
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build draft PDF
uses: openjournals/openjournals-draft-action@master
with:
journal: jose
# This should be the path to the paper within your repo.
paper-path: paper/paper.md
- name: Upload
uses: actions/upload-artifact@v1
with:
name: paper
# This is the output path where Pandoc will write the compiled
# PDF. Note, this should be the same directory as the input
# paper.md
path: paper/paper.pdf

View File

@ -1,15 +0,0 @@
on:
pull_request:
workflow_dispatch:
name: LanguageTool check
jobs:
languagetool_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: reviewdog/action-languagetool@v1
with:
reporter: github-pr-review
level: warning

View File

@ -1,86 +0,0 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: [main]
pull_request:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: pages
cancel-in-progress: true
jobs:
# Single deploy job since we're just deploying
deploy:
permissions: write-all
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Poetry
run: pipx install poetry
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: poetry
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Install Linux Dependencies
run: |
sudo apt-get update
sudo apt-get install libcairo2-dev libpango1.0-dev ffmpeg freeglut3-dev
- name: Install local Python package
run: poetry install --extras=manim --with docs
- name: Restore cached media
id: cache-media-restore
uses: actions/cache/restore@v3
with:
path: media
key: ${{ runner.os }}-media
- name: Build animation and convert it into HTML slides
run: |
poetry run manim example.py ConvertExample BasicExample ThreeDExample
poetry run manim-slides convert ConvertExample docs/source/_static/slides.html -ccontrols=true
poetry run manim-slides convert BasicExample docs/source/_static/basic_example.html -ccontrols=true
poetry run manim-slides convert ThreeDExample docs/source/_static/three_d_example.html -ccontrols=true
- name: Clear cache
run: |
gh extension install actions/gh-actions-cache
gh actions-cache delete ${{ steps.cache-media-restore.outputs.cache-primary-key }} --confirm || true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Save media to cache
id: cache-media-save
uses: actions/cache/save@v3
with:
path: media
key: ${{ steps.cache-media-restore.outputs.cache-primary-key }}
- name: Build docs
run: cd docs && poetry run make html
- name: Upload artifact
if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@v1
with:
# Upload docs/build/html dir
path: docs/build/html/
- name: Deploy to GitHub Pages
id: deployment
if: github.event_name != 'pull_request'
uses: actions/deploy-pages@v1

View File

@ -1,34 +0,0 @@
name: Upload Python Package
on:
push:
release:
types: [published]
jobs:
build_and_release:
name: Build and release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Poetry
run: pipx install poetry
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: poetry
- name: Build wheels
run: poetry build
- name: Publish to PyPI
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
run: poetry publish

View File

@ -1,122 +0,0 @@
on:
pull_request:
paths:
- pyproject.toml
- poetry.lock
- '**.py'
- .github/workflows/test_examples.yml
workflow_dispatch:
name: Test Examples
env:
QT_QPA_PLATFORM: offscreen
MANIM_SLIDES_VERBOSITY: debug
PYTHONFAULTHANDLER: 1
DISPLAY: :99
jobs:
build-examples:
strategy:
fail-fast: false
matrix:
manim: [manim, manimgl]
os: [macos-latest, ubuntu-latest, windows-latest]
pyversion: ['3.8', '3.9', '3.10', '3.11']
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
# We only test Python 3.11 on Windows and MacOS
- os: windows-latest
pyversion: '3.8'
- os: windows-latest
pyversion: '3.9'
- os: windows-latest
pyversion: '3.10'
manim: manim
- os: macos-latest
pyversion: '3.8'
- os: macos-latest
pyversion: '3.9'
- os: macos-latest
pyversion: '3.10'
manim: manim
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Poetry
run: pipx install poetry
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.pyversion }}
cache: poetry
# Path related stuff
- name: Append to Path on MacOS
if: matrix.os == 'macos-latest'
run: |
echo "${HOME}/.local/bin" >> $GITHUB_PATH
echo "/Users/runner/Library/Python/${{ matrix.pyversion }}/bin" >> $GITHUB_PATH
- name: Append to Path on Ubuntu
if: 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
# OS depedencies
- name: Install manim dependencies on MacOs
if: matrix.os == 'macos-latest' && matrix.manim == 'manim'
run: brew install ffmpeg py3cairo
- name: Install manimgl dependencies on MacOS
if: matrix.os == 'macos-latest' && matrix.manim == 'manimgl'
run: brew install ffmpeg
- name: Run apt-get update on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update
- name: Install manim dependencies on Ubuntu
if: matrix.os == 'ubuntu-latest' && matrix.manim == 'manim'
run: |
sudo apt-get install libcairo2-dev libpango1.0-dev ffmpeg freeglut3-dev
- name: Install manimgl dependencies on Ubuntu
if: matrix.os == 'ubuntu-latest' && matrix.manim == 'manimgl'
run: |
sudo apt-get install libpango1.0-dev ffmpeg freeglut3-dev
- name: Install xvfb on Ubuntu
if: matrix.os == 'ubuntu-latest' && matrix.manim == 'manimgl'
run: |
sudo apt-get install xvfb
nohup Xvfb $DISPLAY &
- name: Install Windows dependencies
if: matrix.os == 'windows-latest'
run: choco install ffmpeg
# Install Manim Slides
- name: Install Manim Slides
run: |
poetry config experimental.new-installer false
poetry install --with test
# Render slides
- name: Render slides
if: matrix.manim == 'manim'
run: poetry run manim -ql example.py BasicExample ThreeDExample
- name: Render slides
if: matrix.manim == 'manimgl'
run: poetry run -v manimgl -l example.py BasicExample ThreeDExample
# Play slides
- name: Test slides
run: poetry run manim-slides BasicExample ThreeDExample --skip-all
# Test slides to html
- name: Test convert on Ubuntu
if: matrix.os == 'ubuntu-latest' && matrix.manim == 'manim'
run: |
poetry run manim -ql example.py ConvertExample
poetry run manim-slides convert --to=html ConvertExample index.html

43
.gitignore vendored
View File

@ -1,43 +0,0 @@
__pycache__/
/env
/tests
/build
/dist
*.egg-info/
/media
/presentation
/.vscode
slides/
.manim-slides.json
videos/
images/
docs/build/
docs/source/_static/slides_assets/
docs/source/_static/slides.html
slides_assets/
slides.html
docs/source/_static/basic_example_assets/
docs/source/_static/basic_example.html
docs/source/_static/three_d_example.html
docs/source/_static/three_d_example_assets/
paper/media/
*.jats
paper/paper.pdf

View File

@ -1,34 +0,0 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml
- id: check-toml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.8.0
hooks:
- id: pretty-format-yaml
args: [--autofix]
- id: pretty-format-toml
exclude: poetry.lock
args: [--autofix]
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.263
hooks:
- id: ruff
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.2.0
hooks:
- id: mypy
additional_dependencies: [types-requests, types-setuptools]

1
CNAME Normal file
View File

@ -0,0 +1 @@
manim-slides.readthedocs.io

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 Jérome Eertmans
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

262
README.md
View File

@ -1,260 +1,4 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/logo_dark_transparent.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/logo_light_transparent.png">
<img alt="Manim Slides Logo" src="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/logo.png">
</picture>
# GitHub Pages branch
[![Latest Release][pypi-version-badge]][pypi-version-url]
[![Python version][pypi-python-version-badge]][pypi-version-url]
[![PyPI - Downloads][pypi-download-badge]][pypi-version-url]
[![Documentation][documentation-badge]][documentation-url]
# Manim Slides
Tool for live presentations using either [Manim (community edition)](https://www.manim.community/) or [ManimGL](https://3b1b.github.io/manim/). Manim Slides will *automatically* detect the one you are using!
> **NOTE:** this project extends the work of [`manim-presentation`](https://github.com/galatolofederico/manim-presentation), with a lot more features!
- [Installation](#installation)
* [Dependencies](#dependencies)
* [Pip install](#pip-install)
* [Install From Repository](#install-from-repository)
- [Usage](#usage)
* [Basic Example](#basic-example)
* [Key Bindings](#key-bindings)
* [Interactive Tutorial](#interactive-tutorial)
* [Other Examples](#other-examples)
- [Comparison with Similar Tools](#comparison-with-similar-tools)
- [F.A.Q](#faq)
* [How to increase quality on Windows](#how-to-increase-quality-on-windows)
- [Contributing](#contributing)
* [Reporting an Issue](#reporting-an-issue)
* [Seeking for Help](#seeking-for-help)
* [Contact](#contact)
## Installation
<!-- start install -->
While installing Manim Slides and its dependencies on your global Python is fine, I recommend using a virtual environment (e.g., [venv](https://docs.python.org/3/tutorial/venv.html)) for a local installation.
### Dependencies
<!-- start deps -->
Manim Slides requires either Manim or ManimGL to be installed. Having both packages installed is fine too.
If none of those packages are installed, please refer to their specific installation guidelines:
- [Manim](https://docs.manim.community/en/stable/installation.html)
- [ManimGL](https://3b1b.github.io/manim/getting_started/installation.html)
<!-- end deps -->
### Pip Install
The recommended way to install the latest release is to use pip:
```bash
pip install manim-slides
```
Optionally, you can also install Manim or ManimGL using extras[^1]:
```bash
pip install manim-slides[manim] # For Manim
# or
pip install manim-slides[manimgl] # For ManimGL
```
[^1]: NOTE: you still need to have Manim or ManimGL platform-specific dependencies installed on your computer.
### Install From Repository
An alternative way to install Manim Slides is to clone the git repository, and install from there: read the [contributing guide](https://eertmans.be/manim-slides/contributing/workflow.html) to know how.
<!-- end install -->
## Usage
<!-- start usage -->
Using Manim Slides is a two-step process:
1. Render animations using `Slide` (resp. `ThreeDSlide`) as a base class instead of `Scene` (resp. `ThreeDScene`), and add calls to `self.next_slide()` everytime you want to create a new slide.
2. Run `manim-slides` on rendered animations and display them like a *Power Point* presentation.
The documentation is available [online](https://eertmans.be/manim-slides/).
### Basic Example
Wrap a series of animations between `self.start_loop()` and `self.stop_loop()` when you want to loop them (until input to continue):
```python
# example.py
from manim import *
# or: from manimlib import *
from manim_slides import Slide
class BasicExample(Slide):
def construct(self):
circle = Circle(radius=3, color=BLUE)
dot = Dot()
self.play(GrowFromCenter(circle))
self.next_slide() # Waits user to press continue to go to the next slide
self.start_loop() # Start loop
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop() # This will loop until user inputs a key
self.play(dot.animate.move_to(ORIGIN))
self.next_slide() # Waits user to press continue to go to the next slide
```
First, render the animation files:
```bash
manim example.py BasicExample
# or
manimgl example.py BasicExample
```
To start the presentation using `Scene1`, `Scene2` and so on simply run:
```bash
manim-slides [OPTIONS] Scene1 Scene2...
```
Or in this example:
```bash
manim-slides BasicExample
```
<!-- end usage -->
## Key Bindings
The default key bindings to control the presentation are:
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/wizard_dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/wizard_light.png">
<img alt="Manim Slides Wizard" src="https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/wizard_light.png">
</picture>
You can run the **configuration wizard** to change those key bindings:
```bash
manim-slides wizard
```
A default file can be created with:
```bash
manim-slides init
```
> **_NOTE:_** `manim-slides` uses key codes, which are platform dependent. Using the configuration wizard is therefore highly recommended.
## Interactive Tutorial
Click on the image to watch a slides presentation that explains you how to use Manim Slides.
[![Manim Slides Docs](https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/docs.png)](https://eertmans.be/manim-slides/)
## Other Examples
Other examples are available in the [`example.py`](https://github.com/jeertmans/manim-slides/blob/main/example.py) file, if you downloaded the git repository.
Below is a small recording of me playing with the slides back and forth.
![](https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/example.gif)
## Comparison with Similar Tools
There exists are variety of tools that allows to create slides presentations containing Manim animations.
Below is a comparison of the most used ones with Manim Slides:
| Project name | Manim Slides | Manim Presentation | Manim Editor | Jupyter Notebooks |
|:------------:|:------------:|:------------------:|:------------:|:-----------------:|
| Link | [![GitHub Repo stars](https://img.shields.io/github/stars/jeertmans/manim-slides?style=social)](https://github.com/jeertmans/manim-slides) | [![GitHub Repo stars](https://img.shields.io/github/stars/galatolofederico/manim-presentation?style=social)](https://github.com/galatolofederico/manim-presentation) | [![GitHub Repo stars](https://img.shields.io/github/stars/ManimCommunity/manim_editor?style=social)](https://github.com/ManimCommunity/manim_editor) | [![GitHub Repo stars](https://img.shields.io/github/stars/jupyter/notebook?style=social)](https://github.com/jupyter/notebook) |
| Activity | [![GitHub Repo stars](https://img.shields.io/github/last-commit/jeertmans/manim-slides?style=social)](https://github.com/jeertmans/manim-slides) | [![GitHub Repo stars](https://img.shields.io/github/last-commit/galatolofederico/manim-presentation?style=social)](https://github.com/galatolofederico/manim-presentation) | [![GitHub Repo stars](https://img.shields.io/github/last-commit/ManimCommunity/manim_editor?style=social)](https://github.com/ManimCommunity/manim_editor) | [![GitHub Repo stars](https://img.shields.io/github/last-commit/jupyter/notebook?style=social)](https://github.com/jupyter/notebook) |
| Usage | Command-line | Command-line | Web Browser | Notebook |
| Note | Requires minimal modif. in scenes files | Requires minimal modif. in scenes files | Requires the usage of sections, and configuration through graphical interface | Relies on `nbconvert` to create slides from a Notebook |
| Support for ManimGL | Yes | No | No | No |
| Web Browser presentations | Yes | No | Yes | No |
| Offline presentations | Yes, with Qt | Yes, with OpenCV | No | No
## F.A.Q
### How to increase quality on Windows
On Windows platform, one may encounter a lower image resolution than expected. Usually, this is observed because Windows rescales every application to fit the screen.
As found by [@arashash](https://github.com/arashash), in [#20](https://github.com/jeertmans/manim-slides/issues/20), the problem can be addressed by changing the scaling factor to 100%:
![Windows Fix Scaling](static/windows_quality_fix.png)
in *Settings*->*Display*.
## Contributing
Contributions are more than welcome! Please read through [our contributing section](https://eertmans.be/manim-slides/contributing/index.html).
### Reporting an Issue
<!-- start reporting-an-issue -->
If you think you found a bug,
an error in the documentation,
or wish there was some feature that is currently missing,
we would love to hear from you!
The best way to reach us is via the
[GitHub issues](https://github.com/jeertmans/manim-slides/issues).
If your problem is not covered by an already existing (closed or open) issue,
then we suggest you create a
[new issue](https://github.com/jeertmans/manim-slides/issues/new/choose).
You can choose from a list of templates, or open a
[blank issue](https://github.com/jeertmans/manim-slides/issues/new)
if your issue does not fit one of the proposed topics.
The more precise you are in the description of your problem, the faster we will
be able to help you!
<!-- end reporting-an-issue -->
### Seeking for help
<!-- start seeking-for-help -->
Sometimes, you may have a question about Manim Slides,
not necessarily an issue.
There are two ways you can reach us for questions:
- via the `Question/Help/Support` topic when
[choosing an issue template](https://github.com/jeertmans/manim-slides/issues/new/choose);
- or via
[GitHub discussions](https://github.com/jeertmans/manim-slides/discussions).
<!-- end seeking-for-help -->
### Contact
<!-- start contact -->
Finally, if you do not have any GitHub account,
or just wish to contact the author of Manim Slides,
you can do so at: [jeertmans@icloud.com](mailto:jeertmans@icloud.com).
<!-- end contact -->
[pypi-version-badge]: https://img.shields.io/pypi/v/manim-slides?label=manim-slides
[pypi-version-url]: https://pypi.org/project/manim-slides/
[pypi-python-version-badge]: https://img.shields.io/pypi/pyversions/manim-slides
[pypi-download-badge]: https://img.shields.io/pypi/dm/manim-slides
[documentation-badge]: https://img.shields.io/website?down_color=lightgrey&down_message=offline&label=documentation&up_color=green&up_message=online&url=https%3A%2F%2Feertmans.be%2Fmanim-slides%2F
[documentation-url]: https://eertmans.be/manim-slides/
This branch is kept to keep the https://jeertmans.github.io/manim-slides
link alive, and we redirect to Read The Docs.

View File

@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View File

@ -1 +0,0 @@
../../../static/logo.png

View File

@ -1 +0,0 @@
../../../static/logo_dark_docs.png

View File

@ -1 +0,0 @@
../../../static/logo_dark_github.png

View File

@ -1 +0,0 @@
../../../static/logo_dark_transparent.png

View File

@ -1 +0,0 @@
../../../static/logo_light_transparent.png

View File

@ -1 +0,0 @@
../../../static/wizard_dark.png

View File

@ -1 +0,0 @@
../../../static/wizard_light.png

View File

@ -1,3 +0,0 @@
# Changelog
Changes between releases are listed in Manim Slides' [Github releases](https://github.com/jeertmans/manim-slides/releases). You can read the [latest release here](https://github.com/jeertmans/manim-slides/releases).

View File

@ -1,73 +0,0 @@
# type: ignore
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = "Manim Slides"
copyright = "2023, Jérome Eertmans"
author = "Jérome Eertmans"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.viewcode",
"sphinxext.opengraph",
"sphinx_click",
"myst_parser",
"sphinx_copybutton",
]
myst_enable_extensions = [
"colon_fence",
"html_admonition",
]
templates_path = ["_templates"]
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "furo"
html_static_path = ["_static"]
html_theme_options = {
"light_logo": "logo_light_transparent.png",
"dark_logo": "logo_dark_transparent.png",
"footer_icons": [
{
"name": "GitHub",
"url": "https://github.com/jeertmans/manim-slides",
"html": """
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
</svg>
""",
"class": "",
},
],
"source_repository": "https://github.com/jeertmans/manim-slides/",
"source_branch": "main",
"source_directory": "docs/source/",
}
# -- Intersphinx mapping
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"manim": ("https://docs.manim.community/en/stable/", None),
"manimlib": ("https://3b1b.github.io/manim/", None),
}
# -- OpenGraph settings
ogp_site_url = "https://eertmans.be/manim-slides/"
ogp_use_first_image = True

View File

@ -1,46 +0,0 @@
# Contributing
Thank you for your interest in Manim Slides! ✨
Manim Slides is an open source project, first created as a fork of
[manim-presentation](https://github.com/galatolofederico/manim-presentation)
(now deprecated in favor to Manim Slides),
and we welcome contributions of all forms.
This section is here to help fist-time contributors know how they can help this
project grow. Whether you are already familiar with Manim or GitHub,
it is worth taking a few minutes to read those documents!
```{toctree}
:hidden:
workflow
internals
```
[Workflow](./workflow)
: how to work on this project. Start here if you're a new contributor.
[Internals](./internals)
: how Manim Slides is built and how the various parts of it work.
## Reporting an Issue
```{include} ../../../README.md
:start-after: <!-- start reporting-an-issue -->
:end-before: <!-- end reporting-an-issue -->
```
## Seeking for Help
```{include} ../../../README.md
:start-after: <!-- start seeking-for-help -->
:end-before: <!-- end seeking-for-help -->
```
## Contact
```{include} ../../../README.md
:start-after: <!-- start contact -->
:end-before: <!-- end contact -->
```

View File

@ -1,11 +0,0 @@
# Internals
Manim-Slides' work in split in two steps: first, when rendering animation, and, second, when converting multiple animations into one slides presentation.
## Rendering
To render animations, Manim Slides simply uses Manim or ManimGL, and creates some additional output files that it needs for the presentation.
## Slides presentation
Manim Slides searches for the local artifacts it generated previously, and concatenates them into one presentation. For the graphical interface, it uses `PySide6`.

View File

@ -1,83 +0,0 @@
# Workflow
This document is there to help you recreate a working environment for Manim Slides.
## Dependencies
```{include} ../../../README.md
:start-after: <!-- start deps -->
:end-before: <!-- end deps -->
```
## Forking the repository and cloning it locally
We use GitHub to host Manim Slides' repository, and we encourage contributors to use git.
Useful links:
* [GitHub's Hello World](https://docs.github.com/en/get-started/quickstart/hello-world).
* [GitHub Pull Request in 100 Seconds](https://www.youtube.com/watch?v=8lGpZkjnkt4&ab_channel=Fireship).
Once you feel comfortable with git and GitHub, [fork](https://github.com/jeertmans/manim-slides/fork) the repository, and clone it locally.
As for every Python project, using virtual environment is recommended to avoid conflicts between modules. For Manim Slides, we use [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer). If not already, please install it.
## Installing Python modules
With Poetry, installation becomes straightforward:
```bash
poetry install
```
This, however, only installs the minimal set of dependencies to run the package.
If you would like to install Manim or ManimGL, as documented in the [quickstart](../quickstart),
you can use the `--extras` option:
```bash
poetry install --extras manim # For Manim
# or
poetry install --extras manimgl # For ManimGL
```
Additionnally, Manim Slides comes with group dependencies for development purposes:
```bash
poetry install --with dev # For linters and formatters
# or
poetry install --with docs # To build the documentation locally
```
Another group is `test`, but it is only used for
[GitHub actions](https://github.com/jeertmans/manim-slides/blob/main/.github/workflows/test_examples.yml).
:::{note}
You can combine any number of groups or extras when installing the package locally.
:::
## Running commands
As modules were installed in a new Python environment, you cannot use them directly in the shell.
Instead, you either need to prepend `poetry run` to any command, e.g.:
```bash
poetry run manim-slides wizard
```
or enter a new shell that uses this new Python environment:
```
poetry shell
manim-slides wizard
```
## Testing your code
Most of the tests are done with GitHub actions, thus not on your computer. The only command you should run locally is `pre-commit run --all-files`: this runs a few linter and formatter to make sure the code quality and style stay constant across time. If a warning or an error is displayed, please fix it before going to next step.
## Proposing changes
Once you feel ready and think your contribution is ready to be reviewed, create a [pull request](https://github.com/jeertmans/manim-slides/pulls) and wait for a reviewer to check your work!
Many thanks to you!

View File

@ -1,27 +0,0 @@
# Features Table
The following summarizes the different presentation features Manim Slides offers.
:::{table} Comparison of the different presentation methods.
:widths: auto
:align: center
| Feature / Constraint | [`present`](reference/cli.md) | [`convert --to=html`](reference/cli.md) | [`convert --to=pptx`](reference/cli.md) |
| :--- | :---: | :---: | :---: |
| Basic navigation through slides | Yes | Yes | Yes |
| Replay slide | Yes | No | No |
| Pause animation | Yes | No | No |
| Play slide in reverse | Yes | No | No |
| Slide count | Yes | Yes (optional) | Yes (optional) |
| Animation count | Yes | No | No |
| Needs Python with Manim Slides installed | Yes | No | No |
| Requires internet access | No | Yes | No |
| Auto. play slides | Yes | Yes | Yes |
| Loops support | Yes | Yes | Yes |
| Fully customizable | No | Yes (`--use-template` option) | No |
| Other dependencies | None | A modern web browser | PowerPoint or LibreOffice Impress[^1]
| Works cross-platforms | Yes | Yes | Partly[^1][^2] |
:::
[^1]: If you encounter a problem where slides do not automatically play or loops do not work, please [file an issue on GitHub](https://github.com/jeertmans/manim-slides/issues/new/choose).
[^2]: PowerPoint online does not seem to support automatic playing of videos, so you need LibreOffice Impress on Linux platforms.

View File

@ -1,52 +0,0 @@
---
hide-toc: true
og:description: Manim Slides makes creating slides with Manim super easy!
---
```{eval-rst}
.. image:: _static/logo_light_transparent.png
:width: 600px
:align: center
:class: only-light
:alt: Manim Slide logo
```
```{eval-rst}
.. image:: _static/logo_dark_transparent.png
:width: 600px
:align: center
:class: only-dark
:alt: Manim Slide logo
```
# Welcome to Manim Slide's documentation
Manim Slides makes creating slides with Manim super easy!
In a [very few steps](./quickstart), you can create slides and present them either using the GUI, or your browser.
Slide through the demo below to get a quick glimpse on what you can do with Manin Slides.
<!-- From: https://faq.dailymotion.com/hc/en-us/articles/360022841393-How-to-preserve-the-player-aspect-ratio-on-a-responsive-page -->
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="_static/slides.html"></iframe></div>
```{toctree}
:hidden:
quickstart
reference/index
features_table
```
```{toctree}
:caption: Development
:hidden:
contributing/index
changelog
license
```

View File

@ -1,5 +0,0 @@
# License
```{include} ../../LICENSE.md
```

View File

@ -1,21 +0,0 @@
# Quickstart
## Installation
```{include} ../../README.md
:start-after: <!-- start install -->
:end-before: <!-- end install -->
```
## Creating your first slides
```{include} ../../README.md
:start-after: <!-- start usage -->
:end-before: <!-- end usage -->
```
The output slides should look this this:
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="_static/basic_example.html"></iframe></div>
For more advanced examples, see the [Examples](reference/examples) section.

View File

@ -1,13 +0,0 @@
# Application Programming Interface
Manim Slides' API is very limited: it simply consists of two classes, `Slide` and `ThreeDSlide`, which are subclasses of `Scene` and `ThreeDScene` from Manim.
Thefore, we only document here the methods we think the end-user will ever use, not the methods used internally when rendering.
```{eval-rst}
.. autoclass:: manim_slides.Slide
:members: start_loop, end_loop, pause, next_slide
.. autoclass:: manim_slides.ThreeDSlide
:members:
```

View File

@ -1,10 +0,0 @@
# Command Line Interface
This page contains an exhaustive list of all the commands available with `manim-slides`.
```{eval-rst}
.. click:: manim_slides.__main__:cli
:prog: manim-slides
:nested: full
```

View File

@ -1,80 +0,0 @@
# Examples
Contents of `example.py`.
Do not forget to import Manim Slides and Manim or ManimGL:
```python
from manim import *
from manim_slides import Slide, ThreeDSlide
```
or
```python
from manimlib import *
from manim_slides import Slide, ThreeDSlide
```
Then, each presentation, named `SCENE`, was generated with those two commands:
```bash
manim example.py SCENE # or manimgl example SCENE
manim-slides convert SCENE scene.html -ccontrols=true
```
where `-ccontrols=true` indicates that we want to display the blue navigation arrows.
## Basic Example
Basic example from quickstart.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/basic_example.html"></iframe></div>
```{eval-rst}
.. literalinclude:: ../../../example.py
:language: python
:linenos:
:pyobject: BasicExample
```
## 3D Example
Example using 3D camera. As Manim and ManimGL handle 3D differently, definitions are slightly different.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/three_d_example.html"></iframe></div>
### With Manim
```{eval-rst}
.. literalinclude:: ../../../example.py
:language: python
:linenos:
:dedent: 4
:start-after: [manim-3d]
:end-before: [manim-3d]
```
### With ManimGL
```{eval-rst}
.. literalinclude:: ../../../example.py
:language: python
:linenos:
:dedent: 4
:start-after: [manimgl-3d]
:end-before: [manimgl-3d]
```
## Advanced Example
A more advanced example is `ConvertExample`, which is used as demo slide and tutorial.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/slides.html"></iframe></div>
```{eval-rst}
.. literalinclude:: ../../../example.py
:language: python
:linenos:
:pyobject: ConvertExample
```

View File

@ -1,71 +0,0 @@
# Graphical User Interface
Manim Slides' graphical user interface (GUI) is the *de facto* way to present slides.
If you do not specify one of the commands listed in the [CLI reference](./cli),
Manim Slides will use **present** by default, which launches a GUI window,
playing your scene(s) like so:
```bash
manim-slides [present] [SCENES]...
```
Some optional parameters can be specified and can be listed with:
```bash
manim-slides present --help
```
:::{note}
All the `SCENES` must be in the same folder (`--folder DIRECTORY`), which
defaults to `./slides`. If you rendered your animations without changing
directory, you should not worry about that :-)
:::
## Configuration File
It is possible to configure Manim Slides via a configuration file, even though
this feature is currently limited. You may initiliaze the default configuration
file with:
```bash
manim-slides init
```
:::{warning}
Note that, by default, Manim Slides will use default key bindings that are
platform-dependent. If you decide to overwrite those with a config file, you may
encounter some problems from platform to platform.
:::
## Configuring Key Bindings
If you wish to use other key bindings than the defaults, you can run the
configuration wizard with:
```bash
manim-slides wizard
```
A similar window to the image below will pop up and prompt to change keys.
```{eval-rst}
.. image:: ../_static/wizard_light.png
:width: 300px
:align: center
:class: only-light
:alt: Manim Slide Wizard
```
```{eval-rst}
.. image:: ../_static/wizard_dark.png
:width: 300px
:align: center
:class: only-dark
:alt: Manim Slide Wizard
```
:::{note}
Even though it is not currently supported through the GUI, you can select
multiple key binding for the same action by modifying the config file.
:::

View File

@ -1,40 +0,0 @@
# HTML Presentations
Manim Slides allows you to convert presentations into one HTML file, with
[RevealJS](https://revealjs.com/). This file can then be opened with any modern
web browser, allowing for a nice portability of your presentations.
As with every command with Manim Slides, converting slides' fragments into one
HTML file (and its assets) can be done in one command:
```bash
manim-slides convert [SCENES]... DEST
```
where `DEST` is the `.html` destination file.
## Configuring the Template
Many configuration options are available through the `-c<option>=<value>` syntax.
Most, if not all, RevealJS options should be available by default. If that is
not the case, please
[fill an issue](https://github.com/jeertmans/manim-slides/issues/new/choose)
on GitHub.
You can print the list of available options with:
```bash
manim-slides convert --show-config
```
## Using a Custom Template
The default template used for HTML conversion can be found on
[GitHub](https://github.com/jeertmans/manim-slides/blob/main/manim_slides/data/revealjs_template.html)
or printed with the `--show-template` option.
If you wish to use another template, you can do so with the
`--use-template FILE` option.
## More about HTML Slides
You can read more about HTML slides in the [sharing](./sharing) section.

View File

@ -1,28 +0,0 @@
# Reference Documentation
Automatically generated reference for Manim Slides.
```{toctree}
:hidden:
api
cli
examples
gui
html
sharing
```
[Application Programming Interface](./api): list of classes and methods that may
be useful to the end-user.
[Command Line Interface](./cli): list of all commands available using Manim
Slides' executable.
[Examples](./examples): curated list of examples and their output.
[Graphical User Interface](./gui): details about the main Manim Slide' feature.
[HTML Presenetation](./html): an alternative way of presenting your animations.
[Sharing](./sharing): how to share your presentation with others.

View File

@ -1,163 +0,0 @@
# Sharing your slides
Maybe one of the most important features is the ability to share your
presentation with other people, or even with yourself but on another computer!
There exists a variety of solutions, and all of them are exposed here.
We will go from the *most restrictive* method, to the least restrictive one.
If you need to present on a computer without prior knowledge on what will be
installed on it, please directly refer to the last sections.
> **NOTES:** in the next sections, we will assume your animations are described
in `example.py`, and you have one presentation called `BasicExample`.
## With Manim Slides installed on the target machine
If Manim Slides, Manim (or ManimGL), and their dependencies are installed, then
using `manim-slides present` allows for the best presentations, with the most
options available.
### Sharing your Python file(s)
The lightest way to share your presentation is with the Python files that
describe the slides.
If you have such files, you can recompile the animations locally, and use
`manim-slides present` for your presentation. You may want to copy / paste
you own `.manim-slides.json` config file, but it is **not recommended** if
you are sharing from one platform (e.g., Linux) to another (e.g., Windows) as
the key bindings might not be the same.
Example:
```bash
# If you use ManimGl, replace `manim` with `manimgl`
manim example.py BasicExample
# This or `manim-slides BasicExample` works since
# `present` is implied by default
manim-slides present BasicExample
```
### Sharing your animations files
If you do not want to recompile all the animations, you can simply share the
slides folder (defaults to `./slides`). Then, Manim Slides will be able to read
the animations from this folder and its subdirectories.
Example:
```bash
# Make sure that the slides directory is in the current
# working directory, or specify with `--folder <FOLDER>`
manim-slides present BasicExample
```
and the corresponding tree:
```
.
└── slides
   ├── BasicExample.json
   └── files
     └── BasicExample (files not shown)
```
## Without Manim Slides installed on the target machine
An alternative to `manim-slides present` is `manim-slides convert`.
Currently, HTML and PPTX conversion are available, but do not hesitate to propose
other formats by creating a
[Feature Request](https://github.com/jeertmans/manim-slides/issues/new/choose),
or directly proposing a
[Pull Request](https://github.com/jeertmans/manim-slides/compare).
A major advantage of HTML files is that they can be opened cross-platform,
granted one has a modern web browser (which is pretty standard).
### Sharing HTML and animation files
First, you need to create the HTML file and its assets directory.
Example:
```bash
manim-slides convert BasicExample basic_example.html
```
Then, you need to copy the HTML files and its assets directory to target location,
while keeping the relative path between the HTML and the assets the same. The
easiest solution is to compress both the file and the directory into one ZIP,
and to extract it to the desired location.
By default, the assets directory will be named after the main HTML file, using `{basename}_assets`.
Example:
```
.
├── basic_example_assets
│   ├── 1413466013_2261824125_223132457.mp4
│   ├── 1672018281_2145352439_3942561600.mp4
│   └── 1672018281_3136302242_2191168284.mp4
└── basic_example.html
```
Then, you can simply open the HTML file with any web browser application.
If you want to embed the presentation inside an HTML web page, a possibility is
to use an `iframe`:
```html
<div style="position:relative;padding-bottom:56.25%;">
<!-- 56.25 comes from aspect ratio of 16:9, change this accordingly -->
<iframe
style="width:100%;height:100%;position:absolute;left:0px;top:0px;"
frameborder="0"
width="100%"
height="100%"
allowfullscreen
allow="autoplay"
src="basic_example.html">
</iframe>
</div>
```
The additional code comes from
[this article](https://faq.dailymotion.com/hc/en-us/articles/360022841393-How-to-preserve-the-player-aspect-ratio-on-a-responsive-page)
and it there to preserve the original aspect ratio (16:9).
### Sharing ONE HTML file
A future feature, that will be available once
[#122](https://github.com/jeertmans/manim-slides/issues/122) is solved, will be
to include all animations as data URI encoded, within the HTML file itself.
### Over the internet
Finally, HTML conversion makes it convenient to play your presentation on a
remote server.
This is how your are able to watch all the examples on this website. If you want
to know how to share your slide with GitHub pages, see the
[workflow file](https://github.com/jeertmans/manim-slides/blob/main/.github/workflows/pages.yml).
> **WARNING:** keep in mind that playing large video files over the internet
can take some time, and *glitches* may occur between slide transitions for this
reason.
### With PowerPoint (*EXPERIMENTAL*)
A recent conversion feature is to the PowerPoint format, thanks to the `python-pptx` package. Even though it is fully working, it is still considered in an *EXPERIMENTAL* status because we do not exactly know what versions of PowerPoint (or LibreOffice Impress) are supported.
Basically, you can create a PowerPoint in a single command:
```bash
manim-slides convert --to=pptx BasicExample basic_example.pptx
```
All the videos and necessary files will be contained inside the `.pptx` file, so you can safely share it with anyone. By default, the `poster_frame_image`, i.e., what is displayed by PowerPoint when the video is not playing, is the first frame of each slide. This allows for smooth transitions.
In the future, we hope to provide more features to this format, so feel free to suggest new features too!

View File

@ -1,372 +0,0 @@
# flake8: noqa: F403, F405
# type: ignore
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
class BasicExample(Slide):
def construct(self):
circle = Circle(radius=3, color=BLUE)
dot = Dot()
self.play(GrowFromCenter(circle))
self.next_slide() # Waits user to press continue to go to the next slide
self.start_loop() # Start loop
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop() # This will loop until user inputs a key
self.play(dot.animate.move_to(ORIGIN))
self.next_slide() # Waits user to press continue to go to the next slide
class MultipleAnimationsInLastSlide(Slide):
"""This is used to check against solution for issue #161."""
def construct(self):
circle = Circle(color=BLUE)
dot = Dot()
self.play(GrowFromCenter(circle))
self.play(FadeIn(dot))
self.next_slide()
self.play(dot.animate.move_to(RIGHT))
self.play(dot.animate.move_to(UP))
self.play(dot.animate.move_to(LEFT))
self.play(dot.animate.move_to(DOWN))
self.next_slide()
class TestFileTooLong(Slide):
"""This is used to check against solution for issue #123."""
def construct(self):
import random
circle = Circle(radius=3, color=BLUE)
dot = Dot()
self.play(GrowFromCenter(circle), run_time=0.1)
for _ in range(30):
direction = (random.random() - 0.5) * LEFT + (random.random() - 0.5) * UP
self.play(dot.animate.move_to(direction), run_time=0.1)
self.play(dot.animate.move_to(ORIGIN), run_time=0.1)
self.next_slide()
class ConvertExample(Slide):
"""WARNING: this example does not seem to work with ManimGL."""
def tinywait(self):
self.wait(0.1)
def construct(self):
title = VGroup(
Text("From Manim animations", t2c={"From": BLUE}),
Text("to slides presentation", t2c={"to": BLUE}),
Text("with Manim Slides", t2w={"[-12:]": BOLD}, t2c={"[-13:]": YELLOW}),
).arrange(DOWN)
step_1 = Text("1. In your scenes file, import Manim Slides")
step_2 = Text("2. Replace Scene with Slide")
step_3 = Text("3. In construct, add pauses where you need")
step_4 = Text("4. You can also create loops")
step_5 = Text("5. Render you scene with Manim")
step_6 = Text("6. Open your presentation with Manim Slides")
for step in [step_1, step_2, step_3, step_4, step_5, step_6]:
step.scale(0.5).to_corner(UL)
step = step_1
self.play(FadeIn(title))
self.next_slide()
code = Code(
code="""from manim import *
class Example(Scene):
def construct(self):
dot = Dot()
self.add(dot)
self.play(Indicate(dot, scale_factor=2))
square = Square()
self.play(Transform(dot, square))
self.play(Rotate(square, angle=PI/2))
""",
language="python",
)
code_step_1 = Code(
code="""from manim import *
from manim_slides import Slide
class Example(Scene):
def construct(self):
dot = Dot()
self.add(dot)
self.play(Indicate(dot, scale_factor=2))
square = Square()
self.play(Transform(dot, square))
self.play(Rotate(square, angle=PI/2))
""",
language="python",
)
code_step_2 = Code(
code="""from manim import *
from manim_slides import Slide
class Example(Slide):
def construct(self):
dot = Dot()
self.add(dot)
self.play(Indicate(dot, scale_factor=2))
square = Square()
self.play(Transform(dot, square))
self.play(Rotate(square, angle=PI/2))
""",
language="python",
)
code_step_3 = Code(
code="""from manim import *
from manim_slides import Slide
class Example(Slide):
def construct(self):
dot = Dot()
self.add(dot)
self.play(Indicate(dot, scale_factor=2))
self.next_slide()
square = Square()
self.play(Transform(dot, square))
self.next_slide()
self.play(Rotate(square, angle=PI/2))
""",
language="python",
)
code_step_4 = Code(
code="""from manim import *
from manim_slides import Slide
class Example(Slide):
def construct(self):
dot = Dot()
self.add(dot)
self.start_loop()
self.play(Indicate(dot, scale_factor=2))
self.end_loop()
square = Square()
self.play(Transform(dot, square))
self.next_slide()
self.play(Rotate(square, angle=PI/2))
""",
language="python",
)
code_step_5 = Code(
code="manim example.py Example",
language="console",
)
code_step_6 = Code(
code="manim-slides Example",
language="console",
)
or_text = Text("or generate HTML presentation").scale(0.5)
code_step_7 = Code(
code="manim-slides convert Example slides.html --open",
language="console",
).shift(DOWN)
self.clear()
self.play(FadeIn(code))
self.tinywait()
self.next_slide()
self.play(FadeIn(step, shift=RIGHT))
self.play(Transform(code, code_step_1))
self.tinywait()
self.next_slide()
self.play(Transform(step, step_2))
self.play(Transform(code, code_step_2))
self.tinywait()
self.next_slide()
self.play(Transform(step, step_3))
self.play(Transform(code, code_step_3))
self.tinywait()
self.next_slide()
self.play(Transform(step, step_4))
self.play(Transform(code, code_step_4))
self.tinywait()
self.next_slide()
self.play(Transform(step, step_5))
self.play(Transform(code, code_step_5))
self.tinywait()
self.next_slide()
self.play(Transform(step, step_6))
self.play(Transform(code, code_step_6))
self.play(code.animate.shift(UP), FadeIn(code_step_7), FadeIn(or_text))
self.tinywait()
self.next_slide()
watch_text = Text("Watch result on next slides!").shift(2 * DOWN).scale(0.5)
self.start_loop()
self.play(FadeIn(watch_text))
self.play(FadeOut(watch_text))
self.end_loop()
self.clear()
dot = Dot()
self.add(dot)
self.start_loop()
self.play(Indicate(dot, scale_factor=2))
self.end_loop()
square = Square()
self.play(Transform(dot, square))
self.remove(dot)
self.add(square)
self.tinywait()
self.next_slide()
self.play(Rotate(square, angle=PI / 4))
self.tinywait()
self.next_slide()
learn_more_text = (
VGroup(
Text("Learn more about Manim Slides:"),
Text("https://github.com/jeertmans/manim-slides", color=YELLOW),
)
.arrange(DOWN)
.scale(0.75)
)
self.play(Transform(square, learn_more_text))
self.tinywait()
# For ThreeDExample, things are different
if not MANIMGL:
# [manim-3d]
class ThreeDExample(ThreeDSlide):
def construct(self):
axes = ThreeDAxes()
circle = Circle(radius=3, color=BLUE)
dot = Dot(color=RED)
self.add(axes)
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
self.play(GrowFromCenter(circle))
self.begin_ambient_camera_rotation(rate=75 * DEGREES / 4)
self.next_slide()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=4, rate_func=linear)
self.end_loop()
self.stop_ambient_camera_rotation()
self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES)
self.play(dot.animate.move_to(ORIGIN))
self.next_slide()
self.play(dot.animate.move_to(RIGHT * 3))
self.next_slide()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
self.play(dot.animate.move_to(ORIGIN))
# [manim-3d]
else:
# [manimgl-3d]
# 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.next_slide()
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.next_slide()
self.play(dot.animate.move_to(RIGHT * 3))
self.next_slide()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
self.play(dot.animate.move_to(ORIGIN))
# [manimgl-3d]

View File

@ -1,6 +0,0 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file alias="icon.png">static/icon.png</file>
</qresource>
</RCC>

View File

@ -1,48 +0,0 @@
# flake8: noqa: F401
import sys
from types import ModuleType
from typing import Any, List
from .__version__ import __version__
class module(ModuleType):
def __getattr__(self, name: str) -> Any:
if name == "Slide" or name == "ThreeDSlide":
module = __import__(
"manim_slides.slide", None, None, ["Slide", "ThreeDSlide"]
)
return getattr(module, name)
return ModuleType.__getattribute__(self, name)
def __dir__(self) -> List[str]:
result = list(new_module.__all__)
result.extend(
(
"__file__",
"__doc__",
"__all__",
"__docformat__",
"__name__",
"__path__",
"__package__",
"__version__",
)
)
return result
old_module = sys.modules["manim_slides"]
new_module = sys.modules["manim_slides"] = module("manim_slides")
new_module.__dict__.update(
{
"__file__": __file__,
"__package__": "manim_slides",
"__path__": __path__,
"__doc__": __doc__,
"__version__": __version__,
"__all__": ("__version__", "Slides", "ThreeDSlide"),
}
)

View File

@ -1,74 +0,0 @@
import json
import click
import requests
from click_default_group import DefaultGroup
from .__version__ import __version__
from .convert import convert
from .logger import make_logger
from .present import list_scenes, present
from .wizard import init, wizard
@click.group(cls=DefaultGroup, default="present", default_if_no_args=True)
@click.option(
"--notify-outdated-version/--silent",
" /-S",
is_flag=True,
default=True,
help="Check if a new version of Manim Slides is available.",
)
@click.version_option(__version__, "-v", "--version")
@click.help_option("-h", "--help")
def cli(notify_outdated_version: bool) -> None:
"""
Manim Slides command-line utilities.
If no command is specified, defaults to `present`.
"""
logger = make_logger()
# Code below is mostly a copy from:
# https://github.com/ManimCommunity/manim/blob/main/manim/cli/render/commands.py
if notify_outdated_version:
manim_info_url = "https://pypi.org/pypi/manim-slides/json"
warn_prompt = "Cannot check if latest release of Manim Slides is installed"
try:
req_info: requests.models.Response = requests.get(
manim_info_url, timeout=10
)
req_info.raise_for_status()
stable = req_info.json()["info"]["version"]
if stable != __version__:
click.echo(
"You are using Manim Slides version "
+ click.style(f"v{__version__}", fg="red")
+ ", but version "
+ click.style(f"v{stable}", fg="green")
+ " is available."
)
click.echo(
"You should consider upgrading via "
+ click.style("pip install -U manim-slides", fg="yellow")
)
except requests.exceptions.HTTPError:
logger.debug(f"HTTP Error: {warn_prompt}")
except requests.exceptions.ConnectionError:
logger.debug(f"Connection Error: {warn_prompt}")
except requests.exceptions.Timeout:
logger.debug(f"Timed Out: {warn_prompt}")
except json.JSONDecodeError:
logger.debug(warn_prompt)
logger.debug(f"Error decoding JSON from {manim_info_url}")
except Exception:
logger.debug(f"Something went wrong: {warn_prompt}")
cli.add_command(convert)
cli.add_command(init)
cli.add_command(list_scenes)
cli.add_command(present)
cli.add_command(wizard)
if __name__ == "__main__":
cli()

View File

@ -1 +0,0 @@
__version__ = "4.13.1"

View File

@ -1,82 +0,0 @@
from pathlib import Path
from typing import Any, Callable
import click
from click import Context, Parameter
from .defaults import CONFIG_PATH, FOLDER_PATH
from .logger import logger
F = Callable[..., Any]
Wrapper = Callable[[F], F]
def config_path_option(function: F) -> F:
"""Wraps a function to add configuration path option."""
wrapper: Wrapper = click.option(
"-c",
"--config",
"config_path",
metavar="FILE",
default=CONFIG_PATH,
type=click.Path(dir_okay=False, path_type=Path),
help="Set path to configuration file.",
show_default=True,
)
return wrapper(function)
def config_options(function: F) -> F:
"""Wraps a function to add configuration options."""
function = config_path_option(function)
function = click.option(
"-f", "--force", is_flag=True, help="Overwrite any existing configuration file."
)(function)
function = click.option(
"-m",
"--merge",
is_flag=True,
help="Merge any existing configuration file with the new configuration.",
)(function)
return function
def verbosity_option(function: F) -> F:
"""Wraps a function to add verbosity option."""
def callback(ctx: Context, param: Parameter, value: bool) -> None:
if not value or ctx.resilient_parsing:
return
logger.setLevel(value)
wrapper: Wrapper = click.option(
"-v",
"--verbosity",
type=click.Choice(
["PERF", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
case_sensitive=False,
),
help="Verbosity of CLI output",
default=None,
expose_value=False,
envvar="MANIM_SLIDES_VERBOSITY",
show_envvar=True,
callback=callback,
)
return wrapper(function)
def folder_path_option(function: F) -> F:
"""Wraps a function to add folder path option."""
wrapper: Wrapper = click.option(
"--folder",
metavar="DIRECTORY",
default=FOLDER_PATH,
type=click.Path(exists=True, file_okay=False, path_type=Path),
help="Set slides folder.",
show_default=True,
)
return wrapper(function)

View File

@ -1,261 +0,0 @@
import hashlib
import os
import shutil
import subprocess
import tempfile
from enum import Enum
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
from .logger import logger
def merge_basenames(files: List[FilePath]) -> Path:
"""
Merge multiple filenames by concatenating basenames.
"""
logger.info(f"Generating a new filename for animations: {files}")
dirname: Path = files[0].parent
ext = files[0].suffix
basenames = (file.stem for file in files)
basenames_str = ",".join(f"{len(b)}:{b}" for b in basenames)
# We use hashes to prevent too-long filenames, see issue #123:
# https://github.com/jeertmans/manim-slides/issues/123
basename = hashlib.sha256(basenames_str.encode()).hexdigest()
return dirname.joinpath(basename + ext)
class Key(BaseModel): # type: ignore
"""Represents a list of key codes, with optionally a name."""
ids: Set[int]
name: Optional[str] = None
def set_ids(self, *ids: int) -> None:
self.ids = set(ids)
@validator("ids", each_item=True)
def id_is_posint(cls, v: int) -> int:
if v < 0:
raise ValueError("Key ids cannot be negative integers")
return v
def match(self, key_id: int) -> bool:
m = key_id in self.ids
if m:
logger.debug(f"Pressed key: {self.name}")
return m
class Config(BaseModel): # type: ignore
"""General Manim Slides config"""
QUIT: Key = Key(ids=[Qt.Key_Q], name="QUIT")
CONTINUE: Key = Key(ids=[Qt.Key_Right], name="CONTINUE / NEXT")
BACK: Key = Key(ids=[Qt.Key_Left], name="BACK")
REVERSE: Key = Key(ids=[Qt.Key_V], name="REVERSE")
REWIND: Key = Key(ids=[Qt.Key_R], name="REWIND")
PLAY_PAUSE: Key = Key(ids=[Qt.Key_Space], name="PLAY / PAUSE")
HIDE_MOUSE: Key = Key(ids=[Qt.Key_H], name="HIDE / SHOW MOUSE")
@root_validator
def ids_are_unique_across_keys(cls, values: Dict[str, Key]) -> Dict[str, Key]:
ids: Set[int] = set()
for key in values.values():
if len(ids.intersection(key.ids)) != 0:
raise ValueError(
"Two or more keys share a common key code: please make sure each key has distinct key codes"
)
ids.update(key.ids)
return values
def merge_with(self, other: "Config") -> "Config":
for key_name, key in self:
other_key = getattr(other, key_name)
key.ids.update(other_key.ids)
key.name = other_key.name or key.name
return self
class SlideType(str, Enum):
slide = "slide"
loop = "loop"
last = "last"
class SlideConfig(BaseModel): # type: ignore
type: SlideType
start_animation: int
end_animation: int
number: int
terminated: bool = False
@validator("start_animation", "end_animation")
def index_is_posint(cls, v: int) -> int:
if v < 0:
raise ValueError("Animation index (start or end) cannot be negative")
return v
@validator("number")
def number_is_strictly_posint(cls, v: int) -> int:
if v <= 0:
raise ValueError("Slide number cannot be negative or zero")
return v
@root_validator
def start_animation_is_before_end(
cls, values: Dict[str, Union[SlideType, int, bool]]
) -> Dict[str, Union[SlideType, int, bool]]:
if values["start_animation"] >= values["end_animation"]: # type: ignore
if values["start_animation"] == values["end_animation"] == 0:
raise ValueError(
"You have to play at least one animation (e.g., `self.wait()`) before pausing. If you want to start paused, use the approriate command-line option when presenting. IMPORTANT: when using ManimGL, `self.wait()` is not considered to be an animation, so prefer to directly use `self.play(...)`."
)
raise ValueError(
"Start animation index must be strictly lower than end animation index"
)
return values
def is_slide(self) -> bool:
return self.type == SlideType.slide
def is_loop(self) -> bool:
return self.type == SlideType.loop
def is_last(self) -> bool:
return self.type == SlideType.last
@property
def slides_slice(self) -> slice:
return slice(self.start_animation, self.end_animation)
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(
cls, values: Dict[str, Union[List[SlideConfig], List[FilePath]]]
) -> Dict[str, Union[List[SlideConfig], List[FilePath]]]:
files: List[FilePath] = values.get("files") # type: ignore
slides: List[SlideConfig] = values.get("slides") # type: ignore
if files is None or slides is None:
return values
n_files = len(files)
for slide in slides:
if slide.end_animation > n_files:
raise ValueError(
f"The following slide's contains animations not listed in files {files}: {slide}"
)
return values
def copy_to(self, dest: Path, use_cached: bool = True) -> "PresentationConfig":
"""
Copy the files to a given directory.
"""
n = len(self.files)
for i in range(n):
file = self.files[i]
dest_path = dest / self.files[i].name
self.files[i] = dest_path
if use_cached and dest_path.exists():
logger.debug(f"Skipping copy of {file}, using cached copy")
continue
logger.debug(f"Copying {file} to {dest_path}")
shutil.copy(file, dest_path)
return self
def concat_animations(
self, dest: Optional[Path] = None, use_cached: bool = True
) -> "PresentationConfig":
"""
Concatenate animations such that each slide contains one animation.
"""
dest_paths = []
for i, slide_config in enumerate(self.slides):
files = self.files[slide_config.slides_slice]
slide_config.start_animation = i
slide_config.end_animation = i + 1
if len(files) > 1:
dest_path = merge_basenames(files)
dest_paths.append(dest_path)
if use_cached and dest_path.exists():
logger.debug(f"Concatenated animations already exist for slide {i}")
continue
f = tempfile.NamedTemporaryFile(mode="w", delete=False)
f.writelines(f"file '{os.path.abspath(path)}'\n" for path in files)
f.close()
command: List[str] = [
FFMPEG_BIN,
"-f",
"concat",
"-safe",
"0",
"-i",
f.name,
"-c",
"copy",
str(dest_path),
"-y",
]
logger.debug(" ".join(command))
process = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
output, error = process.communicate()
if output:
logger.debug(output.decode())
if error:
logger.debug(error.decode())
if not dest_path.exists():
raise ValueError(
"could not properly concatenate animations, use `-v INFO` for more details"
)
else:
dest_paths.append(files[0])
self.files = dest_paths
if dest:
return self.copy_to(dest)
return self
DEFAULT_CONFIG = Config()

View File

@ -1,582 +0,0 @@
import os
import platform
import subprocess
import sys
import tempfile
import webbrowser
from enum import Enum
from importlib import resources
from pathlib import Path
from typing import Any, Callable, Dict, Generator, List, Optional, Type, Union
import click
import cv2
import pptx
from click import Context, Parameter
from lxml import etree
from pydantic import BaseModel, FilePath, PositiveInt, ValidationError
from tqdm import tqdm
from . import data
from .commons import folder_path_option, verbosity_option
from .config import PresentationConfig
from .logger import logger
from .present import get_scenes_presentation_config
def open_with_default(file: Path) -> None:
system = platform.system()
if system == "Darwin":
subprocess.call(("open", str(file)))
elif system == "Windows":
os.startfile(str(file)) # type: ignore[attr-defined]
else:
subprocess.call(("xdg-open", str(file)))
def validate_config_option(
ctx: Context, param: Parameter, value: Any
) -> Dict[str, str]:
config = {}
for c_option in value:
try:
key, value = c_option.split("=")
config[key] = value
except ValueError:
raise click.BadParameter(
f"Configuration options `{c_option}` could not be parsed into a proper (key, value) pair. Please use an `=` sign to separate key from value."
)
return config
class Converter(BaseModel): # type: ignore
presentation_configs: List[PresentationConfig] = []
assets_dir: str = "{basename}_assets"
template: Optional[Path] = None
def convert_to(self, dest: Path) -> None:
"""Converts self, i.e., a list of presentations, into a given format."""
raise NotImplementedError
def load_template(self) -> str:
"""Returns the template as a string.
An empty string is returned if no template is used."""
return ""
def open(self, file: Path) -> Any:
"""Opens a file, generated with converter, using appropriate application."""
raise NotImplementedError
@classmethod
def from_string(cls, s: str) -> Type["Converter"]:
"""Returns the appropriate converter from a string name."""
return {
"html": RevealJS,
"pptx": PowerPoint,
}[s]
class Str(str):
"""A simple string, but quoted when needed."""
# This fixes pickling issue on Python 3.8
__reduce_ex__ = str.__reduce_ex__
def __str__(self) -> str:
"""Ensures that the string is correctly quoted."""
if self in ["true", "false", "null"]:
return super().__str__()
else:
return f"'{super().__str__()}'"
Function = str # Basically, anything
class JsTrue(str, Enum):
true = "true"
class JsFalse(str, Enum):
false = "false"
class JsBool(Str, Enum): # type: ignore
true = "true"
false = "false"
class JsNull(Str, Enum): # type: ignore
null = "null"
class ControlsLayout(Str, Enum): # type: ignore
edges = "edges"
bottom_right = "bottom-right"
class ControlsBackArrows(Str, Enum): # type: ignore
faded = "faded"
hidden = "hidden"
visibly = "visibly"
class SlideNumber(Str, Enum): # type: ignore
true = "true"
false = "false"
hdotv = "h.v"
handv = "h/v"
c = "c"
candt = "c/t"
class ShowSlideNumber(Str, Enum): # type: ignore
all = "all"
print = "print"
speaker = "speaker"
class KeyboardCondition(Str, Enum): # type: ignore
null = "null"
focused = "focused"
class NavigationMode(Str, Enum): # type: ignore
default = "default"
linear = "linear"
grid = "grid"
class AutoPlayMedia(Str, Enum): # type: ignore
null = "null"
true = "true"
false = "false"
PreloadIframes = AutoPlayMedia
class AutoAnimateMatcher(Str, Enum): # type: ignore
null = "null"
class AutoAnimateEasing(Str, Enum): # type: ignore
ease = "ease"
AutoSlide = Union[PositiveInt, JsFalse]
class AutoSlideMethod(Str, Enum): # type: ignore
null = "null"
MouseWheel = Union[JsNull, float]
class Transition(Str, Enum): # type: ignore
none = "none"
fade = "fade"
slide = "slide"
convex = "convex"
concave = "concave"
zoom = "zoom"
class TransitionSpeed(Str, Enum): # type: ignore
default = "default"
fast = "fast"
slow = "slow"
class BackgroundSize(Str, Enum): # type: ignore
# From: https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
# TODO: support more background size
contain = "contain"
cover = "cover"
BackgroundTransition = Transition
class Display(Str, Enum): # type: ignore
block = "block"
class RevealTheme(str, Enum):
black = "black"
white = "white"
league = "league"
beige = "beige"
sky = "sky"
night = "night"
serif = "serif"
simple = "simple"
soralized = "solarized"
blood = "blood"
moon = "moon"
class RevealJS(Converter):
# Presentation size options from RevealJS
width: Union[Str, int] = Str("100%")
height: Union[Str, int] = Str("100%")
margin: float = 0.04
min_scale: float = 0.2
max_scale: float = 2.0
# Configuration options from RevealJS
controls: JsBool = JsBool.false
controls_tutorial: JsBool = JsBool.true
controls_layout: ControlsLayout = ControlsLayout.bottom_right
controls_back_arrows: ControlsBackArrows = ControlsBackArrows.faded
progress: JsBool = JsBool.false
slide_number: SlideNumber = SlideNumber.false
show_slide_number: Union[ShowSlideNumber, Function] = ShowSlideNumber.all
hash_one_based_index: JsBool = JsBool.false
hash: JsBool = JsBool.false
respond_to_hash_changes: JsBool = JsBool.false
history: JsBool = JsBool.false
keyboard: JsBool = JsBool.true
keyboard_condition: Union[KeyboardCondition, Function] = KeyboardCondition.null
disable_layout: JsBool = JsBool.false
overview: JsBool = JsBool.true
center: JsBool = JsBool.true
touch: JsBool = JsBool.true
loop: JsBool = JsBool.false
rtl: JsBool = JsBool.false
navigation_mode: NavigationMode = NavigationMode.default
shuffle: JsBool = JsBool.false
fragments: JsBool = JsBool.true
fragment_in_url: JsBool = JsBool.true
embedded: JsBool = JsBool.false
help: JsBool = JsBool.true
pause: JsBool = JsBool.true
show_notes: JsBool = JsBool.false
auto_play_media: AutoPlayMedia = AutoPlayMedia.null
preload_iframes: PreloadIframes = PreloadIframes.null
auto_animate: JsBool = JsBool.true
auto_animate_matcher: Union[AutoAnimateMatcher, Function] = AutoAnimateMatcher.null
auto_animate_easing: AutoAnimateEasing = AutoAnimateEasing.ease
auto_animate_duration: float = 1.0
auto_animate_unmatched: JsBool = JsBool.true
auto_animate_styles: List[str] = [
"opacity",
"color",
"background-color",
"padding",
"font-size",
"line-height",
"letter-spacing",
"border-width",
"border-color",
"border-radius",
"outline",
"outline-offset",
]
auto_slide: AutoSlide = 0
auto_slide_stoppable: JsBool = JsBool.true
auto_slide_method: Union[AutoSlideMethod, Function] = AutoSlideMethod.null
default_timing: Union[JsNull, int] = JsNull.null
mouse_wheel: JsBool = JsBool.false
preview_links: JsBool = JsBool.false
post_message: JsBool = JsBool.true
post_message_events: JsBool = JsBool.false
focus_body_on_page_visibility_change: JsBool = JsBool.true
transition: Transition = Transition.none
transition_speed: TransitionSpeed = TransitionSpeed.default
background_size: BackgroundSize = BackgroundSize.contain # Not in RevealJS
background_transition: BackgroundTransition = BackgroundTransition.none
pdf_max_pages_per_slide: Union[int, str] = "Number.POSITIVE_INFINITY"
pdf_separate_fragments: JsBool = JsBool.true
pdf_page_height_offset: int = -1
view_distance: int = 3
mobile_view_distance: int = 2
display: Display = Display.block
hide_inactive_cursor: JsBool = JsBool.true
hide_cursor_time: int = 5000
# Add. options
background_color: str = "black" # TODO: use pydantic.color.Color
reveal_version: str = "4.4.0"
reveal_theme: RevealTheme = RevealTheme.black
title: str = "Manim Slides"
class Config:
use_enum_values = True
extra = "forbid"
def get_sections_iter(self, assets_dir: Path) -> Generator[str, None, None]:
"""Generates a sequence of sections, one per slide, that will be included into the html template."""
for presentation_config in self.presentation_configs:
for slide_config in presentation_config.slides:
file = presentation_config.files[slide_config.start_animation]
file = assets_dir / file.name
# TODO: document this
# Videos are muted because, otherwise, the first slide never plays correctly.
# This is due to a restriction in playing audio without the user doing anything.
# Later, this might be useful to only mute the first video, or to make it optional.
# 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'<section data-background-size={self.background_size.value} data-background-color="{presentation_config.background_color}" data-background-video="{file}" data-background-video-muted data-background-video-loop></section>'
else:
yield f'<section data-background-size={self.background_size.value} data-background-color="{presentation_config.background_color}" data-background-video="{file}" data-background-video-muted></section>'
def load_template(self) -> str:
"""Returns the RevealJS HTML template as a string."""
if isinstance(self.template, Path):
return self.template.read_text()
if sys.version_info < (3, 9):
return resources.read_text(data, "revealjs_template.html")
return resources.files(data).joinpath("revealjs_template.html").read_text()
def open(self, file: Path) -> bool:
return webbrowser.open(file.absolute().as_uri())
def convert_to(self, dest: Path) -> None:
"""Converts this configuration into a RevealJS HTML presentation, saved to DEST."""
dirname = dest.parent
basename = dest.stem
ext = dest.suffix
assets_dir = Path(
self.assets_dir.format(dirname=dirname, basename=basename, ext=ext)
)
full_assets_dir = dirname / assets_dir
os.makedirs(full_assets_dir, exist_ok=True)
for presentation_config in self.presentation_configs:
presentation_config.concat_animations().copy_to(full_assets_dir)
with open(dest, "w") as f:
sections = "".join(self.get_sections_iter(assets_dir))
revealjs_template = self.load_template()
content = revealjs_template.format(sections=sections, **self.dict())
f.write(content)
class PowerPoint(Converter):
left: PositiveInt = 0
top: PositiveInt = 0
width: PositiveInt = 1280
height: PositiveInt = 720
auto_play_media: bool = True
poster_frame_image: Optional[FilePath] = None
class Config:
use_enum_values = True
extra = "forbid"
def open(self, file: Path) -> None:
return open_with_default(file)
def convert_to(self, dest: Path) -> None:
"""Converts this configuration into a PowerPoint presentation, saved to DEST."""
prs = pptx.Presentation()
prs.slide_width = self.width * 9525
prs.slide_height = self.height * 9525
layout = prs.slide_layouts[6] # Should be blank
# From GitHub issue comment:
# - https://github.com/scanny/python-pptx/issues/427#issuecomment-856724440
def auto_play_media(
media: pptx.shapes.picture.Movie, loop: bool = False
) -> None:
el_id = xpath(media.element, ".//p:cNvPr")[0].attrib["id"]
el_cnt = xpath(
media.element.getparent().getparent().getparent(),
'.//p:timing//p:video//p:spTgt[@spid="%s"]' % el_id,
)[0]
cond = xpath(el_cnt.getparent().getparent(), ".//p:cond")[0]
cond.set("delay", "0")
if loop:
ctn = xpath(el_cnt.getparent().getparent(), ".//p:cTn")[0]
ctn.set("repeatCount", "indefinite")
def xpath(el: etree.Element, query: str) -> etree.XPath:
nsmap = {"p": "http://schemas.openxmlformats.org/presentationml/2006/main"}
return etree.ElementBase.xpath(el, query, namespaces=nsmap)
def save_first_image_from_video_file(file: Path) -> Optional[str]:
cap = cv2.VideoCapture(str(file))
ret, frame = cap.read()
if ret:
f = tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".png")
cv2.imwrite(f.name, frame)
return f.name
else:
logger.warn("Failed to read first image from video file")
return None
for i, presentation_config in enumerate(self.presentation_configs):
presentation_config.concat_animations()
for slide_config in tqdm(
presentation_config.slides,
desc=f"Generating video slides for config {i + 1}",
leave=False,
):
file = presentation_config.files[slide_config.start_animation]
if self.poster_frame_image is None:
poster_frame_image = save_first_image_from_video_file(file)
else:
poster_frame_image = str(self.poster_frame_image)
slide = prs.slides.add_slide(layout)
movie = slide.shapes.add_movie(
str(file),
self.left,
self.top,
self.width * 9525,
self.height * 9525,
poster_frame_image=poster_frame_image,
mime_type="video/mp4",
)
if self.auto_play_media:
auto_play_media(movie, loop=slide_config.is_loop())
prs.save(dest)
def show_config_options(function: Callable[..., Any]) -> Callable[..., Any]:
"""Wraps a function to add a `--show-config` option."""
def callback(ctx: Context, param: Parameter, value: bool) -> None:
if not value or ctx.resilient_parsing:
return
to = ctx.params.get("to", "html")
converter = Converter.from_string(to)(presentation_configs=[])
for key, value in converter.dict().items():
click.echo(f"{key}: {repr(value)}")
ctx.exit()
return click.option( # type: ignore
"--show-config",
is_flag=True,
help="Show supported options for given format and exit.",
default=None,
expose_value=False,
show_envvar=True,
callback=callback,
)(function)
def show_template_option(function: Callable[..., Any]) -> Callable[..., Any]:
"""Wraps a function to add a `--show-template` option."""
def callback(ctx: Context, param: Parameter, value: bool) -> None:
if not value or ctx.resilient_parsing:
return
to = ctx.params.get("to", "html")
template = ctx.params.get("template", None)
converter = Converter.from_string(to)(
presentation_configs=[], template=template
)
click.echo(converter.load_template())
ctx.exit()
return click.option( # type: ignore
"--show-template",
is_flag=True,
help="Show the template (currently) used for a given conversion format and exit.",
default=None,
expose_value=False,
show_envvar=True,
callback=callback,
)(function)
@click.command()
@click.argument("scenes", nargs=-1)
@folder_path_option
@click.argument("dest", type=click.Path(dir_okay=False, path_type=Path))
@click.option(
"--to",
type=click.Choice(["html", "pptx"], case_sensitive=False),
default="html",
show_default=True,
help="Set the conversion format to use.",
)
@click.option(
"--open",
"open_result",
is_flag=True,
help="Open the newly created file using the approriate application.",
)
@click.option("-f", "--force", is_flag=True, help="Overwrite any existing file.")
@click.option(
"-c",
"--config",
"config_options",
multiple=True,
callback=validate_config_option,
help="Configuration options passed to the converter. E.g., pass `-cslide_number=true` to display slide numbers.",
)
@click.option(
"--use-template",
"template",
metavar="FILE",
type=click.Path(exists=True, dir_okay=False, path_type=Path),
help="Use the template given by FILE instead of default one. To echo the default template, use `--show-template`.",
)
@show_template_option
@show_config_options
@verbosity_option
def convert(
scenes: List[str],
folder: Path,
dest: Path,
to: str,
open_result: bool,
force: bool,
config_options: Dict[str, str],
template: Optional[Path],
) -> None:
"""
Convert SCENE(s) into a given format and writes the result in DEST.
"""
presentation_configs = get_scenes_presentation_config(scenes, folder)
try:
converter = Converter.from_string(to)(
presentation_configs=presentation_configs,
template=template,
**config_options,
)
converter.convert_to(dest)
if open_result:
converter.open(dest)
except ValidationError as e:
errors = e.errors()
msg = [
f"{len(errors)} error(s) occured with configuration options for '{to}', see below."
]
for error in errors:
option = error["loc"][0]
_msg = error["msg"]
msg.append(f"Option '{option}': {_msg}")
raise click.UsageError("\n".join(msg))

View File

@ -1,291 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>{title}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/reveal.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/theme/{reveal_theme}.min.css">
<!-- Theme used for syntax highlighting of code -->
<!-- <link rel="stylesheet" href="lib/css/zenburn.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/zenburn.min.css">
<!-- <link rel="stylesheet" href="index.css"> -->
</head>
<body>
<div class="reveal">
<div class="slides">
{sections}
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/reveal.min.js"></script>
<!-- To include plugins, see: https://revealjs.com/plugins/ -->
<!-- <script src="index.js"></script> -->
<script>
Reveal.initialize({{
// The "normal" size of the presentation, aspect ratio will
// be preserved when the presentation is scaled to fit different
// resolutions. Can be specified using percentage units.
width: {width},
height: {height},
// Factor of the display size that should remain empty around
// the content
margin: {margin},
// Bounds for smallest/largest possible scale to apply to content
minScale: {min_scale},
maxScale: {max_scale},
// Display presentation control arrows
controls: {controls},
// Help the user learn the controls by providing hints, for example by
// bouncing the down arrow when they first encounter a vertical slide
controlsTutorial: {controls_tutorial},
// Determines where controls appear, "edges" or "bottom-right"
controlsLayout: {controls_layout},
// Visibility rule for backwards navigation arrows; "faded", "hidden"
// or "visible"
controlsBackArrows: {controls_back_arrows},
// Display a presentation progress bar
progress: {progress},
// Display the page number of the current slide
// - true: Show slide number
// - false: Hide slide number
//
// Can optionally be set as a string that specifies the number formatting:
// - "h.v": Horizontal . vertical slide number (default)
// - "h/v": Horizontal / vertical slide number
// - "c": Flattened slide number
// - "c/t": Flattened slide number / total slides
//
// Alternatively, you can provide a function that returns the slide
// number for the current slide. The function should take in a slide
// object and return an array with one string [slideNumber] or
// three strings [n1,delimiter,n2]. See #formatSlideNumber().
slideNumber: {slide_number},
// Can be used to limit the contexts in which the slide number appears
// - "all": Always show the slide number
// - "print": Only when printing to PDF
// - "speaker": Only in the speaker view
showSlideNumber: {show_slide_number},
// Use 1 based indexing for # links to match slide number (default is zero
// based)
hashOneBasedIndex: {hash_one_based_index},
// Add the current slide number to the URL hash so that reloading the
// page/copying the URL will return you to the same slide
hash: {hash},
// Flags if we should monitor the hash and change slides accordingly
respondToHashChanges: {respond_to_hash_changes},
// Push each slide change to the browser history. Implies `hash: true`
history: {history},
// Enable keyboard shortcuts for navigation
keyboard: {keyboard},
// Optional function that blocks keyboard events when retuning false
//
// If you set this to 'focused', we will only capture keyboard events
// for embedded decks when they are in focus
keyboardCondition: {keyboard_condition},
// Disables the default reveal.js slide layout (scaling and centering)
// so that you can use custom CSS layout
disableLayout: {disable_layout},
// Enable the slide overview mode
overview: {overview},
// Vertical centering of slides
center: {center},
// Enables touch navigation on devices with touch input
touch: {touch},
// Loop the presentation
loop: {loop},
// Change the presentation direction to be RTL
rtl: {rtl},
// Changes the behavior of our navigation directions.
//
// "default"
// Left/right arrow keys step between horizontal slides, up/down
// arrow keys step between vertical slides. Space key steps through
// all slides (both horizontal and vertical).
//
// "linear"
// Removes the up/down arrows. Left/right arrows step through all
// slides (both horizontal and vertical).
//
// "grid"
// When this is enabled, stepping left/right from a vertical stack
// to an adjacent vertical stack will land you at the same vertical
// index.
//
// Consider a deck with six slides ordered in two vertical stacks:
// 1.1 2.1
// 1.2 2.2
// 1.3 2.3
//
// If you're on slide 1.3 and navigate right, you will normally move
// from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
// from 1.3 -> 2.3.
navigationMode: {navigation_mode},
// Randomizes the order of slides each time the presentation loads
shuffle: {shuffle},
// Turns fragments on and off globally
fragments: {fragments},
// Flags whether to include the current fragment in the URL,
// so that reloading brings you to the same fragment position
fragmentInURL: {fragment_in_url},
// Flags if the presentation is running in an embedded mode,
// i.e. contained within a limited portion of the screen
embedded: {embedded},
// Flags if we should show a help overlay when the question-mark
// key is pressed
help: {help},
// Flags if it should be possible to pause the presentation (blackout)
pause: {pause},
// Flags if speaker notes should be visible to all viewers
showNotes: {show_notes},
// Global override for autolaying embedded media (video/audio/iframe)
// - null: Media will only autoplay if data-autoplay is present
// - true: All media will autoplay, regardless of individual setting
// - false: No media will autoplay, regardless of individual setting
autoPlayMedia: {auto_play_media},
// Global override for preloading lazy-loaded iframes
// - null: Iframes with data-src AND data-preload will be loaded when within
// the viewDistance, iframes with only data-src will be loaded when visible
// - true: All iframes with data-src will be loaded when within the viewDistance
// - false: All iframes with data-src will be loaded only when visible
preloadIframes: {preload_iframes},
// Can be used to globally disable auto-animation
autoAnimate: {auto_animate},
// Optionally provide a custom element matcher that will be
// used to dictate which elements we can animate between.
autoAnimateMatcher: {auto_animate_matcher},
// Default settings for our auto-animate transitions, can be
// overridden per-slide or per-element via data arguments
autoAnimateEasing: {auto_animate_easing},
autoAnimateDuration: {auto_animate_duration},
autoAnimateUnmatched: {auto_animate_unmatched},
// CSS properties that can be auto-animated. Position & scale
// is matched separately so there's no need to include styles
// like top/right/bottom/left, width/height or margin.
autoAnimateStyles: {auto_animate_styles},
// Controls automatic progression to the next slide
// - 0: Auto-sliding only happens if the data-autoslide HTML attribute
// is present on the current slide or fragment
// - 1+: All slides will progress automatically at the given interval
// - false: No auto-sliding, even if data-autoslide is present
autoSlide: {auto_slide},
// Stop auto-sliding after user input
autoSlideStoppable: {auto_slide_stoppable},
// Use this method for navigation when auto-sliding (defaults to navigateNext)
autoSlideMethod: {auto_slide_method},
// Specify the average time in seconds that you think you will spend
// presenting each slide. This is used to show a pacing timer in the
// speaker view
defaultTiming: {default_timing},
// Enable slide navigation via mouse wheel
mouseWheel: {mouse_wheel},
// Opens links in an iframe preview overlay
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
// individually
previewLinks: {preview_links},
// Exposes the reveal.js API through window.postMessage
postMessage: {post_message},
// Dispatches all reveal.js events to the parent window through postMessage
postMessageEvents: {post_message_events},
// Focuses body when page changes visibility to ensure keyboard shortcuts work
focusBodyOnPageVisibilityChange: {focus_body_on_page_visibility_change},
// Transition style
transition: {transition}, // none/fade/slide/convex/concave/zoom
// Transition speed
transitionSpeed: {transition_speed}, // default/fast/slow
// Transition style for full page slide backgrounds
backgroundTransition: {background_transition}, // none/fade/slide/convex/concave/zoom
// The maximum number of pages a single slide can expand onto when printing
// to PDF, unlimited by default
pdfMaxPagesPerSlide: {pdf_max_pages_per_slide},
// Prints each fragment on a separate slide
pdfSeparateFragments: {pdf_separate_fragments},
// Offset used to reduce the height of content within exported PDF pages.
// This exists to account for environment differences based on how you
// print to PDF. CLI printing options, like phantomjs and wkpdf, can end
// on precisely the total height of the document whereas in-browser
// printing has to end one pixel before.
pdfPageHeightOffset: {pdf_page_height_offset},
// Number of slides away from the current that are visible
viewDistance: {view_distance},
// Number of slides away from the current that are visible on mobile
// devices. It is advisable to set this to a lower number than
// viewDistance in order to save resources.
mobileViewDistance: {mobile_view_distance},
// The display mode that will be used to show slides
display: {display},
// Hide cursor if inactive
hideInactiveCursor: {hide_inactive_cursor},
// Time before the cursor is hidden (in ms)
hideCursorTime: {hide_cursor_time}
}});
</script>
</body>
</html>

View File

@ -1,3 +0,0 @@
FOLDER_PATH: str = "./slides"
CONFIG_PATH: str = ".manim-slides.json"
FFMPEG_BIN: str = "ffmpeg"

View File

@ -1,47 +0,0 @@
"""
Logger utils, mostly copied from Manim Community:
https://github.com/ManimCommunity/manim/blob/d5b65b844b8ce8ff5151a2f56f9dc98cebbc1db4/manim/_config/logger_utils.py#L29-L101
"""
import logging
from rich.console import Console
from rich.logging import RichHandler
from rich.theme import Theme
__all__ = ["logger", "make_logger"]
HIGHLIGHTED_KEYWORDS = [ # these keywords are highlighted specially
"Played",
"animations",
"scene",
"Reading",
"Writing",
"script",
"arguments",
"Invalid",
"Aborting",
"module",
"File",
"Rendering",
"Rendered",
]
def make_logger() -> logging.Logger:
"""
Make a logger similar to the one used by Manim.
"""
RichHandler.KEYWORDS = HIGHLIGHTED_KEYWORDS
rich_handler = RichHandler(
show_time=True,
console=Console(theme=Theme({"logging.level.perf": "magenta"})),
)
logging.addLevelName(5, "PERF")
logger = logging.getLogger("manim-slides")
logger.addHandler(rich_handler)
return logger
logger = logging.getLogger("manim-slides")

View File

@ -1,81 +0,0 @@
import os
import sys
from contextlib import contextmanager
from importlib.util import find_spec
from typing import Iterator
__all__ = [
"MANIM",
"MANIM_PACKAGE_NAME",
"MANIM_AVAILABLE",
"MANIM_IMPORTED",
"MANIMGL",
"MANIMGL_PACKAGE_NAME",
"MANIMGL_AVAILABLE",
"MANIMGL_IMPORTED",
"logger",
"Scene",
"ThreeDScene",
"config",
"FFMPEG_BIN",
]
@contextmanager
def suppress_stdout() -> Iterator[None]:
with open(os.devnull, "w") as devnull:
old_stdout = sys.stdout
sys.stdout = devnull
try:
yield
finally:
sys.stdout = old_stdout
MANIM_PACKAGE_NAME = "manim"
MANIM_AVAILABLE = find_spec(MANIM_PACKAGE_NAME) is not None
MANIM_IMPORTED = MANIM_PACKAGE_NAME in sys.modules
MANIMGL_PACKAGE_NAME = "manimlib"
MANIMGL_AVAILABLE = find_spec(MANIMGL_PACKAGE_NAME) is not None
MANIMGL_IMPORTED = MANIMGL_PACKAGE_NAME in sys.modules
if MANIM_IMPORTED and MANIMGL_IMPORTED:
from manim import logger
logger.warn(
"Both manim and manimgl are installed, therefore `manim-slide` needs to need which one to use. Please only import one of the two modules so that `manim-slide` knows which one to use. Here, manim is used by default"
)
MANIM = True
MANIMGL = False
elif MANIM_IMPORTED:
MANIM = True
MANIMGL = False
elif MANIMGL_IMPORTED:
MANIM = False
MANIMGL = True
elif MANIM_AVAILABLE:
MANIM = True
MANIMGL = False
elif MANIMGL_AVAILABLE:
MANIM = False
MANIMGL = True
else:
raise ModuleNotFoundError(
"Either manim (community) or manimgl (3b1b) package must be installed"
)
if MANIMGL:
from manimlib import Scene, ThreeDScene, config
from manimlib.constants import FFMPEG_BIN
from manimlib.logger import log as logger
else:
with suppress_stdout(): # Avoids printing "Manim Community v..."
from manim import Scene, ThreeDScene, config, logger
try: # For manim<v0.16.0.post0
from manim.constants import FFMPEG_BIN
except ImportError:
FFMPEG_BIN = config.ffmpeg_executable

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +0,0 @@
# type: ignore
# Resource object code (Python 3)
# Created by: object code
# Created by: The Resource Compiler for Qt version 6.4.0
# WARNING! All changes made in this file will be lost!
from PySide6 import QtCore
qt_resource_data = b"\
\x00\x00\x08\x1c\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
\x00\x01\x00\x00\x00\x01\x00\x08\x06\x00\x00\x00\x5cr\xa8f\
\x00\x00\x01\x84iCCPICC prof\
ile\x00\x00(\x91}\x91=H\xc3@\x1c\xc5_\
S\xa5R+\x0e\xed \xe2\x90\xa1:Y\x10-\xe2\xa8\
U(B\x85P+\xb4\xea`r\xfd\x84&\x0dI\x8a\
\x8b\xa3\xe0Zp\xf0c\xb1\xea\xe0\xe2\xac\xab\x83\xab \
\x08~\x808:9)\xbaH\x89\xffK\x0a-b<\
8\xee\xc7\xbb{\x8f\xbbw\x80\xd0\xac2\xd5\xec\x99\x00\
T\xcd2\xd2\xc9\x84\x98\xcd\xad\x8a\x81W\x04\x11F?\
\xe2\x88\xcb\xcc\xd4\xe7$)\x05\xcf\xf1u\x0f\x1f_\xef\
b<\xcb\xfb\xdc\x9fc _0\x19\xe0\x13\x89g\x99\
nX\xc4\x1b\xc4\xd3\x9b\x96\xcey\x9f8\xc2\xcar\x9e\
\xf8\x9cx\xdc\xa0\x0b\x12?r]q\xf9\x8ds\xc9a\
\x81gF\x8cLz\x9e8B,\x96\xbaX\xe9bV\
6T\xe28q4\xafj\x94/d]\xces\xde\xe2\
\xacV\xeb\xac}O\xfe\xc2PA[Y\xe6:\xcd\x11\
$\xb1\x88%H\x10\xa1\xa0\x8e\x0a\xaa\xb0\x10\xa3U#\
\xc5D\x9a\xf6\x13\x1e\xfea\xc7/\x91K!W\x05\x8c\
\x1c\x0b\xa8A\x85\xec\xf8\xc1\xff\xe0w\xb7fqj\xd2\
M\x0a%\x80\xde\x17\xdb\xfe\x18\x05\x02\xbb@\xaba\xdb\
\xdf\xc7\xb6\xdd:\x01\xfc\xcf\xc0\x95\xd6\xf1\xd7\x9a\xc0\xcc\
'\xe9\x8d\x8e\x16=\x02\x06\xb7\x81\x8b\xeb\x8e\xa6\xec\x01\
\x97;\xc0\xd0\x93.\x1b\xb2#\xf9i\x0a\xc5\x22\xf0~\
F\xdf\x94\x03\xc2\xb7@p\xcd\xed\xad\xbd\x8f\xd3\x07 \
C]\xa5n\x80\x83C`\xacD\xd9\xeb\x1e\xef\xee\xeb\
\xee\xed\xdf3\xed\xfe~\x00\xd6\xd3r\xcf+\xa2\xc1_\
\x00\x00\x00\x06bKGD\x004\x004\x004\xaf4\
\x1c\xc0\x00\x00\x00\x09pHYs\x00\x00.#\x00\x00\
.#\x01x\xa5?v\x00\x00\x00\x07tIME\x07\
\xe6\x0a\x13\x0c\x0f\x03\x13^\x06\xfe\x00\x00\x00\x19tE\
XtComment\x00Create\
d with GIMPW\x81\x0e\x17\x00\
\x00\x05\xf4IDATx\xda\xed\xddA\x92\x9b:\x18\
\x85QK\xe5%\xc1\xfe\x17\x00{rF\x19\xa4\xcb\xee\
\x801X\xd2=g\x98z\x956 }\xfe\xd5\xddy\
\xbe\xdd\x00\x00\x00\x00\x00\x801\x95\xab\xbe\xd04M\x0f\
\xb7\x1b\xb6[\xd7\xb5t\x1d\x00\x9b\x1e\xda\x8eA\xb1\xf1\
!7\x04\xc5\xc6\x87\xdc\x10\x14\x1b\x1fr#Pl~\
\xc8\x0dA\xb1\xf9!7\x02\xc5\xe6\x87\xdc\x08\x14\x9b\x1f\
r#Pl~\xc8\x8d@\xb1\xf9!7\x02\xc5\xe6\x87\
\xdc\x08T\x9b\x1frU\xb7\x00\xc6\xb4\xe5\x8d\xbb|\xe2\
/\x01\xfa<\x0aT\x9b\x1f\x1c\x01\x80\xc0\xa3@\xf5\xee\
\x0f&\x00 p\x0a\xa8\xde\xfd\xc1\x04\x00\x04N\x01\x02\
\x00&\x00@\x00\x9c\xff!\xca\xbd\x85\x17\xb1,\x8b'\
A\x9cy\x9e\xb3\x03`\xe3\x93\xec\xef\xfa\xfff\x08\xaa\
\xcd\x0f\xb9\x13p\xb5\xf9!7\x02~\x0a\x00\xc1.\x0f\
\x80w\x7fhgo\x98\x00\xc0\x04\x00\x08\x00 \x00\x80\
\x00\x00\x02\x00\x08\x00 \x00\x80\x00\x00\x02\x00\x08\x00 \
\x00\x80\x00\x00\x02\x00\x08\x00 \x00\x80\x00\x00\x02\x00\x08\
\x00 \x00\x80\x00\x00\x02\x00\x08\x00 \x00\x80\x00\x00\x02\
\x00|\xd2\xbd\xb7\x17\xfc\xdbG)\x8f\xfc\xb1c-^\
\xb7g\xd1\xffu\x97\x9f\x7f0M\xd3\xe3\xcc/x\xe4\
\x06m\xfd\x1c\xf5\x91\x16_\x8b\xd7\xbc\xe7\xf3\xec\x13\x9f\
\xc5\x91\xeb\xde\xf35\xde\xb1\xaek\xe9\xf2\x08\xb0\xe7\xc6\
\x9c}\x13\x93\xafy\xef\xd7I|\x16=]w\x1d\xf1\
\xe6\x8f\xb0\xf0Z\xbc\xe6w\xff\xfe\xc4g\xd1\x8b\xea\xe6\
\xb7w\xbdG\xae\xb9\xd5\xfb\x95\xf6\x1c{\xb9\xe6\xea\x01\
x\xbd\xae/\xf7\x99\xf81\xa0\x85v\xe9\xeb;:\xe1\
\x006\xbfkF\x00l\x04\xd7\x8e\x00t\xbc\xf8m\
\x00\x11\x10\x00\x8b\xde\xfd\x10C\x01\xb0\xf9qo\x04\xc0\
\x02w\x8f\xdc\x04\x01\xb0\xb0\xdd+\x04\xc0\xf9V\x04\x10\
\x00\x8bX<\x11\x00\x9b\xdf\xbdD\x00,X\xf7\x14\x01\
\xb0P\xdd[\x04\xc0yU\x04\x10\x00\x8bRl\x11\x00\
\x9b\xdf\xbdG\x00,@\xcf\x00\x01\xb0\xf0<\x0b\x04\xc0\
\xf9S\x04\x10\x00\x8b\xcc\xf3A\x00,.\x13\x1a\x02`\
\xf3{f\x08\x80\x85\xe4\xd9\x09\x00FI\x11\x10\x00,\
\x1a1\x17\x00\x8b\x05\xcfV\x00,\x10<c\x01\xb00\
\xf0\xac\x05\xc0\xf9\x10\x11\x10\x00\x8b\x00\xf1\x17\x00\x9b\x1f\
kA\x00<p\xac\x09\x01\xf0\xa0\xb16\x04\xc0y\x0f\
\x11\x10\x00\x0f\x15\xeb\xa5\x1bw\x0f\x13r\xd7\x8d_\x04\
\x82`\x02\x00\x02\x00\x08\x00 \x00\x80\x00\x00\x02\x00\x08\
\x00 \x00\x80\x00\x00\x02\xd0\xbeeY<e\xac\x9d\xe4\
\x09@\x04\xb0f\xc2\x8f\x00\xcb\xb2\x08\x016\x7f\xfa\xf7\
\x00D\x00o\x12\xc1\x01\x10\x01\xac\x89\xf0\x00\x88\x00\xd6\
Bx\x00D\x00k\xc0\xef\x01\xf8\xe6\xa0\xcd/\x00X\
\x0c\x9e\xb7\x00X\x14\x16\x85\x89O\x00,\x10<[\x01\
\xb0P\xf0L\x05\xc0\xa8\x88\xcd/\x00\x16\x0f\x9e\x9f\x00\
XD\x98\xe0\x04@\x04\xf0\xac\x04\xc0\xc2\xc23\x12\x00\
\xa3%6\xbf\x00Xlx\x1e\x02`\xd1a\x22\x13\x00\
\x11\xc0\xbd\x17\x00\x0b\x11\xf7\x5c\x00\x8c\xa2\xd8\xfc\x02`\
q\xe2\xfe\x0a\x80E\x8a\x09K\x00D\x00\xf7R\x00,\
\x5c\xdcC\x010\xbab\xf3\x0b\x80\xc5\x8c\xfb%\x00\x16\
\xb5\xfb\x84\x00X\xdc\x8eK\x08\x80\x08\xb8'\x08\x80w\
;\x9b\x1f\x01\xb0\xf8]?\x02`\x13\x98\x80\x10\x00\x11\
p\xad\x08\xc0\x08\x0b\xad\xe5\xd7\xfb\xa9\xd7f\xf3\x0b\x80\
\x05s\xe2h\x9c\x10\x11\xaf9l\x02x\xe7!\xf4\xfe\
\xe0Z\xbc\xe6Q\xc3t\xd6k\xef\xe1\x9a\xeb\x88\x0fa\
\x94j\xb7x\xcd{\xbfN\xea7\xfbz\xb9\xe6:\xd2\
M\x1dq\xb1m\xb9\xa6\xab\xafy\xeb\xd7\x1b\xe9Y\xec\
Y[=]w\xf9\xf9\x07\xd34=\x94\x91\xad\xe6y\
\x8e|\xc6g]\xf7\xb3\xbf\xf7\x93\xd6u\xfdg\xcf\xdf\
-a\x04=\xf7\xba\xfd\x1e\x00\x04\x13\x00\x10\x00@\x00\
\x00\x01\x00\x04\x00\x10\x00@\x00\x00\x01\x00\x04\x00\x10\x00\
@\x00\x00\x01\x00\x04\x00\x10\x00@\x00\x00\x01\x00\x04\x00\
\x10\x00@\x00\x00\x01\x00\x04\x00\x18=\x00g\xff\x7f\xcf\
\xa1W\xdf\xd8\x1b5\xe5B\xc1\xe6o\xe8\x08 \x02\xf0\
\xfd\xbdPS/\x1c\xd27\xff\xed\xf6\xe4\xb3\x01o\xb7\
\xf3?\x1f\xf0\x15\x9f\x1b\x88M\x7f\xae\xa6?\x1b\xd0D\
0V<=\xcf\xf6\xf91\xe0@\xef*6\x1c\x02 \
\x04n\x02\x9b\xc6\xff\x97\x01x\xf6\x1f\x22\x02\x98\x00p\
$ !\x00\xa6\x00\xd3\x00c\x8f\xff&\x00\x11 \xdc\
\x7f\xdf\xe5\xbf\xf5;\x01\x9c\xe3\xca\x1f\x17\x0aO\xdb\xef\
\xfe\x9b&\x00G\x01\xd3\x00cn~G\x00\x11\xc0\x11\
`\x1bG\x01G\x02\xa1\x19\xeb\xdd\x7f\xd7\x04\xe0(`\
\x1a`\xac\xcd\xbf\xfb\x08 \x02\x22\xc08\x9b\x7f\xd7\x11\
\xc0q\xc0\x91@X\xc6\xda\xfc\xbb'\x00\x93\x80i\x80\
q6\xff\xdb\x01\x10\x01\x11\xa0\xff\xcd\xff\xf6\x11\xc0q\
\xc0\x91@H\xfa\xdf\xfc\x87&\x00\x93\x80i\x80\xbe7\
\xffG&\x00\xd3\x80I@<\xfa\xdb\xf8\xa7\x04@\x08\
\x84@\x00\xfa\xd8\xf8\xa7\x06@\x08D@\x00\xda\xde\xf8\
\x97\x04@\x08\xb2# \x00\xedn\xfcK\x03 \x08\x99\
\x11\x10\x80\xf66|\x13\x01`\xach\xbe\x0a\xc1\xd9\x01\
\xf0\x13\xa8\xe3\xfcs`\xef\x0c\x87y\xa7\x17\x00D@\
\x08\x04\x80+\x22`\x1a@\x00\x84@\x048\xcc7Q\
:\x97\xfc\x13\x15\xdf\x044\x01\x98\x04l\x02L\x00$\
N\x03\xe2g\x02\xc0\x86@\x00\x10\x01\x1c\x01\x88:\x12\
\x88\x9d\x09\x00\x1b\x04\x01@\x04p\x04 \xeaH n\
&\x00l\x18\x04\x00\x11\xc0\x11\x80\xa8#\x81\x98\x99\x00\
\xb0\x81\x10\x00D\x00G\x00\xa2\x8e\x04\xe2e\x02\xc0\x86\
B\x00\x10\x01\x1c\x01\x88:\x12\x88\x95\x09\x00\x1b\x0c\x01\
@\x04p\x04 \xeaH N&\x00l8\x04\x00\x11\
\xc0\x11\x80\xa8#\x81\x18\x99\x00\xb0\x01\x11\x00D\x00G\
\x00\xa2\x8e\x04\xe2c\x02\xc04\x80\x09\x80\xc4i@p\
L\x00\x98\x06\x10\x00D\x00\x01@\x04\xf0=\x002\xbe\
/ .&\x00L\x03\x08\x00\x22\x80#\x00QG\x02\
11\x01`\x1a@\x00\x10\x01\x1c\x01\x88:\x12\x88\x87\
\x00\x10\x1a\x01\x9b_\x00\x08\x8d\x80\xcd\x0fA1\xe8\xfd\
S\x8c\x01\x00\xda\xf2\x07\xc0\xb4\x09d\x9d\x1fRw\x00\
\x00\x00\x00IEND\xaeB`\x82\
"
qt_resource_name = b"\
\x00\x08\
\x0aaZ\xa7\
\x00i\
\x00c\x00o\x00n\x00.\x00p\x00n\x00g\
"
qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x847\x9eu\x9f\
"
def qInitResources():
QtCore.qRegisterResourceData(
0x03, qt_resource_struct, qt_resource_name, qt_resource_data
)
def qCleanupResources():
QtCore.qUnregisterResourceData(
0x03, qt_resource_struct, qt_resource_name, qt_resource_data
)
qInitResources()

View File

@ -1,368 +0,0 @@
import os
import platform
import shutil
import subprocess
from typing import Any, List, Optional, Tuple
from warnings import warn
from tqdm import tqdm
from .config import PresentationConfig, SlideConfig, SlideType
from .defaults import FOLDER_PATH
from .manim import FFMPEG_BIN, MANIMGL, Scene, ThreeDScene, config, logger
def reverse_video_file(src: str, dst: str) -> None:
"""Reverses a video file, writting the result to `dst`."""
command = [FFMPEG_BIN, "-i", src, "-vf", "reverse", dst]
logger.debug(" ".join(command))
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = process.communicate()
if output:
logger.debug(output.decode())
if error:
logger.debug(error.decode())
class Slide(Scene): # type:ignore
"""
Inherits from :class:`manim.scene.scene.Scene` or :class:`manimlib.scene.scene.Scene` and provide necessary tools for slides rendering.
"""
def __init__(
self, *args: Any, output_folder: str = FOLDER_PATH, **kwargs: Any
) -> None:
if MANIMGL:
if not os.path.isdir("videos"):
os.mkdir("videos")
kwargs["file_writer_config"] = {
"break_into_partial_movies": True,
"output_directory": "",
"write_to_movie": True,
}
kwargs["preview"] = False
super().__init__(*args, **kwargs)
self.__output_folder = output_folder
self.__slides: List[SlideConfig] = []
self.__current_slide = 1
self.__current_animation = 0
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."""
if MANIMGL:
return self.camera_config["pixel_width"], self.camera_config["pixel_height"]
else:
return config["pixel_width"], config["pixel_height"]
@property
def __partial_movie_files(self) -> List[str]:
"""Returns a list of partial movie files, a.k.a animations."""
if MANIMGL:
from manimlib.utils.file_ops import get_sorted_integer_files
kwargs = {
"remove_non_integer_files": True,
"extension": self.file_writer.movie_file_extension,
}
return get_sorted_integer_files( # type: ignore
self.file_writer.partial_movie_directory, **kwargs
)
else:
return self.renderer.file_writer.partial_movie_files # type: ignore
@property
def __show_progress_bar(self) -> bool:
"""Returns True if progress bar should be displayed."""
if MANIMGL:
return getattr(self, "show_progress_bar", True)
else:
return config["progress_bar"] != "none" # type: ignore
@property
def __leave_progress_bar(self) -> bool:
"""Returns True if progress bar should be left after completed."""
if MANIMGL:
return getattr(self, "leave_progress_bars", False)
else:
return config["progress_bar"] == "leave" # type: ignore
@property
def __start_at_animation_number(self) -> Optional[int]:
if MANIMGL:
return getattr(self, "start_at_animation_number", None)
else:
return config["from_animation_number"] # type: ignore
def play(self, *args: Any, **kwargs: Any) -> None:
"""Overloads `self.play` and increment animation count."""
super().play(*args, **kwargs)
self.__current_animation += 1
def next_slide(self) -> None:
"""
Creates a new slide with previous animations.
This usually means that the user will need to press some key before the
next slide is played. By default, this is the right arrow key.
.. note::
Calls to :func:`next_slide` at the very beginning or at the end are
not needed, since they are automatically added.
.. warning::
This is not allowed to call :func:`next_slide` inside a loop.
Examples
--------
The following contains 3 slides:
#. the first with nothing on it;
#. the second with "Hello World!" fading in;
#. and the last with the text fading out;
.. code-block:: python
from manim import *
from manim_slides import Slide
class Example(Slide):
def construct(self):
text = Text("Hello World!")
self.next_slide()
self.play(FadeIn(text))
self.next_slide()
self.play(FadeOut(text))
"""
assert (
self.__loop_start_animation is None
), "You cannot call `self.next_slide()` inside a loop"
self.__slides.append(
SlideConfig(
type=SlideType.slide,
start_animation=self.__pause_start_animation,
end_animation=self.__current_animation,
number=self.__current_slide,
)
)
self.__current_slide += 1
self.__pause_start_animation = self.__current_animation
def pause(self) -> None:
"""
Creates a new slide with previous animations.
.. deprecated:: 4.10.0
Use :func:`next_slide` instead.
"""
warn(
"`self.pause()` is deprecated. Use `self.next_slide()` instead.",
DeprecationWarning,
stacklevel=2,
)
Slide.next_slide(self)
def __add_last_slide(self) -> None:
"""Adds a 'last' slide to the end of slides."""
if (
len(self.__slides) > 0
and self.__current_animation == self.__slides[-1].end_animation
):
self.__slides[-1].type = SlideType.last
return
self.__slides.append(
SlideConfig(
type=SlideType.last,
start_animation=self.__pause_start_animation,
end_animation=self.__current_animation,
number=self.__current_slide,
)
)
def start_loop(self) -> None:
"""
Starts a loop. End it with :func:`end_loop`.
A loop will automatically replay the slide, i.e., everything between
:func:`start_loop` and :func:`end_loop`, upon reaching end.
Examples
--------
The following contains one slide that will loop endlessly.
.. code-block:: python
from manim import *
from manim_slides import Slide
class Example(Slide):
def construct(self):
dot = Dot(color=BLUE)
self.start_loop()
self.play(Indicate(dot))
self.end_loop()
"""
assert self.__loop_start_animation is None, "You cannot nest loops"
self.__loop_start_animation = self.__current_animation
def end_loop(self) -> None:
"""Ends an existing loop. See :func:`start_loop` for more details."""
assert (
self.__loop_start_animation is not None
), "You have to start a loop before ending it"
self.__slides.append(
SlideConfig(
type=SlideType.loop,
start_animation=self.__loop_start_animation,
end_animation=self.__current_animation,
number=self.__current_slide,
)
)
self.__current_slide += 1
self.__loop_start_animation = None
self.__pause_start_animation = self.__current_animation
def __save_slides(self, use_cache: bool = True) -> None:
"""
Saves slides, optionally using cached files.
Note that cached files only work with Manim.
"""
self.__add_last_slide()
if not os.path.exists(self.__output_folder):
os.mkdir(self.__output_folder)
files_folder = os.path.join(self.__output_folder, "files")
if not os.path.exists(files_folder):
os.mkdir(files_folder)
scene_name = str(self)
scene_files_folder = os.path.join(files_folder, scene_name)
old_animation_files = set()
if not os.path.exists(scene_files_folder):
os.mkdir(scene_files_folder)
elif not use_cache:
shutil.rmtree(scene_files_folder)
os.mkdir(scene_files_folder)
else:
old_animation_files.update(os.listdir(scene_files_folder))
files = []
for src_file in tqdm(
self.__partial_movie_files,
desc=f"Copying animation files to '{scene_files_folder}' and generating reversed animations",
leave=self.__leave_progress_bar,
ascii=True if platform.system() == "Windows" else None,
disable=not self.__show_progress_bar,
):
if src_file is None and not MANIMGL:
# This happens if rendering with -na,b (manim only)
# where animations not in [a,b] will be skipped
# but animations before a will have a None src_file
continue
filename = os.path.basename(src_file)
rev_filename = "{}_reversed{}".format(*os.path.splitext(filename))
dst_file = os.path.join(scene_files_folder, filename)
# We only copy animation if it was not present
if filename in old_animation_files:
old_animation_files.remove(filename)
else:
shutil.copyfile(src_file, dst_file)
# We only reverse video if it was not present
if rev_filename in old_animation_files:
old_animation_files.remove(rev_filename)
else:
rev_file = os.path.join(scene_files_folder, rev_filename)
reverse_video_file(src_file, rev_file)
files.append(dst_file)
if offset := self.__start_at_animation_number:
self.__slides = [
slide for slide in self.__slides if slide.end_animation > offset
]
for slide in self.__slides:
slide.start_animation -= offset
slide.end_animation -= offset
logger.info(
f"Copied {len(files)} animations to '{os.path.abspath(scene_files_folder)}' and generated reversed animations"
)
slide_path = os.path.join(self.__output_folder, "%s.json" % (scene_name,))
with open(slide_path, "w") as f:
f.write(
PresentationConfig(
slides=self.__slides,
files=files,
resolution=self.__resolution,
background_color=self.__background_color,
).json(indent=2)
)
logger.info(
f"Slide '{scene_name}' configuration written in '{os.path.abspath(slide_path)}'"
)
def run(self, *args: Any, **kwargs: Any) -> None:
"""MANIMGL renderer"""
super().run(*args, **kwargs)
self.__save_slides(use_cache=False)
def render(self, *args: Any, **kwargs: Any) -> None:
"""MANIM render"""
# We need to disable the caching limit since we rely on intermediate files
max_files_cached = config["max_files_cached"]
config["max_files_cached"] = float("inf")
super().render(*args, **kwargs)
config["max_files_cached"] = max_files_cached
self.__save_slides()
class ThreeDSlide(Slide, ThreeDScene): # type: ignore
"""
Inherits from :class:`Slide` and :class:`manim.scene.three_d_scene.ThreeDScene` or :class:`manimlib.scene.three_d_scene.ThreeDScene` and provide necessary tools for slides rendering.
.. note:: ManimGL does not need ThreeDScene for 3D rendering in recent versions, see `example.py`.
"""
pass

View File

@ -1,195 +0,0 @@
import os
import sys
from functools import partial
from typing import Any
import click
from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon, QKeyEvent
from PySide6.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QGridLayout,
QLabel,
QMessageBox,
QPushButton,
QVBoxLayout,
QWidget,
)
from .commons import config_options, verbosity_option
from .config import Config, Key
from .defaults import CONFIG_PATH
from .logger import logger
from .resources import * # noqa: F401, F403
WINDOW_NAME: str = "Configuration Wizard"
keymap = {}
for key in Qt.Key:
keymap[key.value] = key.name.partition("_")[2]
class KeyInput(QDialog): # type: ignore
def __init__(self) -> None:
super().__init__()
self.key = None
self.layout = QVBoxLayout()
self.setWindowTitle("Keyboard Input")
self.label = QLabel("Press any key to register it")
self.layout.addWidget(self.label)
self.setLayout(self.layout)
def keyPressEvent(self, event: QKeyEvent) -> None:
self.key = event.key()
self.deleteLater()
event.accept()
class Wizard(QWidget): # type: ignore
def __init__(self, config: Config):
super().__init__()
self.setWindowTitle(WINDOW_NAME)
self.config = config
self.icon = QIcon(":/icon.png")
self.setWindowIcon(self.icon)
QBtn = QDialogButtonBox.Save | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.saveConfig)
self.buttonBox.rejected.connect(self.closeWithoutSaving)
self.buttons = []
self.layout = QGridLayout()
for i, (key, value) in enumerate(self.config.dict().items()):
# Create label for key name information
label = QLabel()
key_info = value["name"] or key
label.setText(key_info)
self.layout.addWidget(label, i, 0)
# Create button that will pop-up a dialog and ask to input a new key
value = value["ids"].pop()
button = QPushButton(keymap[value])
button.setToolTip(
f"Click to modify the key associated to action {key_info}"
)
self.buttons.append(button)
button.clicked.connect(
partial(self.openDialog, i, getattr(self.config, key))
)
self.layout.addWidget(button, i, 1)
self.layout.addWidget(self.buttonBox, len(self.buttons), 1)
self.setLayout(self.layout)
def closeWithoutSaving(self) -> None:
logger.debug("Closing configuration wizard without saving")
self.deleteLater()
sys.exit(0)
def closeEvent(self, event: Any) -> None:
self.closeWithoutSaving()
event.accept()
def saveConfig(self) -> None:
try:
Config.parse_obj(self.config.dict())
except ValueError:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setText("Error")
msg.setInformativeText(
"Two or more actions share a common key: make sure actions have distinct key codes."
)
msg.setWindowTitle("Error: duplicated keys")
msg.exec_()
return
self.deleteLater()
def openDialog(self, button_number: int, key: Key) -> None:
button = self.buttons[button_number]
dialog = KeyInput()
dialog.exec_()
if dialog.key is not None:
key_name = keymap[dialog.key]
key.set_ids(dialog.key)
button.setText(key_name)
@click.command()
@config_options
@click.help_option("-h", "--help")
@verbosity_option
def wizard(config_path: str, force: bool, merge: bool) -> None:
"""Launch configuration wizard."""
return _init(config_path, force, merge, skip_interactive=False)
@click.command()
@config_options
@click.help_option("-h", "--help")
@verbosity_option
def init(
config_path: str, force: bool, merge: bool, skip_interactive: bool = False
) -> None:
"""Initialize a new default configuration file."""
return _init(config_path, force, merge, skip_interactive=True)
def _init(
config_path: str, force: bool, merge: bool, skip_interactive: bool = False
) -> None:
"""Actual initialization code for configuration file, with optional interactive mode."""
if os.path.exists(config_path):
click.secho(f"The `{CONFIG_PATH}` configuration file exists")
if not force and not merge:
choice = click.prompt(
"Do you want to continue and (o)verwrite / (m)erge it, or (q)uit?",
type=click.Choice(["o", "m", "q"], case_sensitive=False),
)
force = choice == "o"
merge = choice == "m"
if not force and not merge:
logger.debug("Exiting without doing anything")
sys.exit(0)
config = Config()
if force:
logger.debug(f"Overwriting `{config_path}` if exists")
elif merge:
logger.debug("Merging new config into `{config_path}`")
if not skip_interactive:
if os.path.exists(config_path):
config = Config.parse_file(config_path)
app = QApplication(sys.argv)
app.setApplicationName("Manim Slides Wizard")
window = Wizard(config)
window.show()
app.exec()
config = window.config
if merge:
config = Config.parse_file(config_path).merge_with(config)
with open(config_path, "w") as config_file:
config_file.write(config.json(indent=2))
click.secho(f"Configuration file successfully saved to `{config_path}`")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 MiB

View File

@ -1,53 +0,0 @@
@online{manim-announcement,
author = {Grant Sanderson},
title = {{Q}\&{A} with {G}rant {S}anderson (3blue1brown)},
year = {2018},
organization = {YouTube},
url = {https://www.youtube.com/watch?v=Qe6o9j4IjTo\&ab_channel=3Blue1Brown}
}
@misc{revealjs,
author = {Hakim El Hattab},
title = {The HTML Presentation Framework},
year = {2022},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/hakimel/reveal.js}
}
@misc{manim-presentation,
author = {Federico Galatolo},
title = {Tool for live presentations using manim},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/galatolofederico/manim-presentation}
}
@misc{manimgl,
author = {Grant Sanderson},
title = {Animation engine for explanatory math videos},
year = {2022},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/3b1b/manim}
}
@misc{manim-editor,
author = {Christopher Besch},
title = {Web Presenter for Mathematical Animations using Manim},
year = {2022},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/ManimCommunity/manim_editor}
}
@software{manimce,
author = {{The Manim Community Developers}},
license = {MIT},
month = {12},
title = {{Manim Mathematical Animation Framework}},
url = {https://www.manim.community/},
version = {v0.17.2},
year = {2022}
}

View File

@ -1,147 +0,0 @@
---
title: 'Manim Slides: A Python package for presenting Manim content anywhere'
tags:
- Python
- manim
- animations
- teaching
- conference presentations
- tool
authors:
- name: Jérome Eertmans
orcid: 0000-0002-5579-5360
affiliation: 1
affiliations:
- name: ICTEAM, UCLouvain, Belgium
index: 1
date: 2 March 2023
bibliography: paper.bib
---
# Summary
Manim Slides is a Python package that makes presenting Manim animations
straightforward. With minimal changes required to pre-existing code, one can
slide through animations in a *PowerPoint-like* manner, or share its slides
*online* using ReavealJS' power.
# Introduction
Presenting educational content has always been a difficult task, especially
when it uses temporal or iterative concepts. During the last decades, the
presence of computers in classrooms for educational purposes has increased
enormously, allowing teachers to show animated or interactive content.
With the democratization of YouTube, many people have decided to use this
platform to share educational content. Among these people, Grant Sanderson, a
YouTuber presenting videos on the theme of mathematics, quickly became known
for his original and quality animations. In 2018, Grant announced in a video
that he creates his animations using a self-developed Python tool called Manim
[@manim-announcement]. In 2019, he made the Manim source code public [@manimgl],
so anyone can use his tool. Very quickly, the community came together and, in
2020, created a "fork" of the original GitHub repository [@manimce], in order to
create a more accessible and better documented version of this tool. Since then,
the two versions are differentiated by using ManimGL for Grant Sanderson's
version, as it uses OpenGL for rendering, and ManimCE for the community edition
(CE).
Despite the many advantages of the Manim tool in terms of illustrating
mathematical concepts, one cannot help but notice that most presentations,
whether in the classroom or at a conference, are mainly done with PowerPoint
or PDF slides. One of the many advantages of these formats, as opposed to videos
created with Manim, is the ability to pause, rewind, etc., whenever you want.
To face this problem, in 2021, the manim-presentation tool was created
[@manim-presentation]. This tool allows you to present Manim animations as you
would present slides: with pauses, slide jumps, etc. However, this tool has
evolved very little since its inception and does not work with ManimGL.
In 2022, Manim Slides has been created from manim-presentation, with the aim
to make it a more complete tool, better documented, and usable on all platforms
and with ManimCE or ManimGL. After almost a year of existence, Manim Slides has
evolved a lot, has built a small community of contributors, and continues to
provide new features on a regular basis.
# Easy to Use Commitment
Manim Slides is commited to be an easy-to-use tool, with minimal installation
procedure and few modifications required. It can either be used locally with its
graphical user interface (GUI), or shared via one of the two formats it can
convert to:
* an HTML page thanks to the RevealJS Javascript package [@revealjs];
* or a PowerPoint (`.pptx`) file.
This work has a very similar syntax to Manim and offers a comprehensive
documentation hosted on [GitHub pages](https://jeertmans.github.io/manim-slides/), see
\autoref{fig:docs}.
![Manim Slides' documentation homepage.\label{fig:docs}](docs.png)
# Example usage
We have used manim-presentation for our presentation at the COST
Interact, hosted in Lyon, 2022, and
[available online](https://web.archive.org/web/20230507184944/https://eertmans.be/posts/cost-interact-presentation/).
This experience highly motivated the development of Manim Slides, and our
EuCAP 2023 presentation slides are already
[available online](https://web.archive.org/web/20230507211243/https://eertmans.be/posts/eucap-presentation/), thanks
to Manim Slides' HTML feature.
Also, one of our users created a short
[video tutorial](https://www.youtube.com/watch?v=Oc9g89VzKsY&ab_channel=TheoremofBeethoven)
and posted it on YouTube.
# Stability and releases
Manim Slides is continously tested on most recent Python versions, both ManimCE
and ManimGL, and on all major platforms: **Ubuntu**, **macOS** and **Windows**. Due to Manim
Slide's exposed API being very minimal, and the variety of tests that are
performed, this tool can be considered stable over time.
New releases are very frequent, as they mostly introduce enhancements or small
documention fixes, and the command-line tool automatically notifies for new
available updates. Therefore, regularly updating Manim Slides is highly
recommended.
# Statement of Need
Similar tools to Manim Slides also exist, such as its predecessor,
manim-presentation [@manim-presentation], or the web-based alternative, Manim
Editor [@manim-editor], but none of them provide the documentation level nor the
amount of features that Manim Slides strives to. This work makes the task of
presenting Manim content in front of an audience much easier than before,
allowing presenters to focus more on the content of their slides, rather than on
how to actually present them efficiently.
## Target Audience
Manim Slides was developed with the goal of making educational content more
accessible than ever. We believe that researchers, professors, teaching
assistants and anyone else who needs to teach scientific content can benefit
from using this tool. The ability to pace your presentation yourself is
essential, and Manim Slides gives you that ability.
## A Need for Portability
One of the major concerns with presenting content in a non-standard format
(i.e., not just a plain PDF) is the issue of portability.
Depending on the programs available, the power of the target computer,
or the access to the internet, not all solutions are equal.
From the same configuration file, Manim Slides offers a series of solutions to
share your slides, which we discuss on our
[Sharing your slides](https://jeertmans.github.io/manim-slides/reference/sharing.html)
page.
# Acknowledgements
We acknowledge the work of [@manim-presentation] that paved the initial structure
of Manim Slides with the manim-presentation Python package.
We also acknowledge Grant Sanderson for his tremendous work on Manim, as
well as the Manim Community contributors.
Finally, we also acknowledge contributions from the GitHub contributors on the
Manim Slides repository.
# References

2985
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
[build-system]
build-backend = "poetry.core.masonry.api"
requires = ["setuptools", "poetry-core>=1.0.0"]
[tool.black]
target-version = ["py38"]
[tool.isort]
profile = "black"
py_version = 38
[tool.mypy]
disallow_untyped_decorators = false
install_types = true
python_version = "3.8"
strict = true
[tool.poetry]
authors = [
"Jérome Eertmans <jeertmans@icloud.com>"
]
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Topic :: Multimedia :: Video",
"Topic :: Multimedia :: Graphics",
"Topic :: Scientific/Engineering"
]
description = "Tool for live presentations using manim"
documentation = "https://eertmans.be/manim-slides"
exclude = ["docs/", "static/"]
homepage = "https://github.com/jeertmans/manim-slides"
keywords = ["manim", "slides", "plugin", "manimgl"]
license = "MIT"
name = "manim-slides"
packages = [
{include = "manim_slides"}
]
readme = "README.md"
repository = "https://github.com/jeertmans/manim-slides"
version = "4.13.1"
[tool.poetry.dependencies]
click = "^8.1.3"
click-default-group = "^1.2.2"
lxml = "^4.9.2"
manim = {version = "^0.17.0", optional = true}
manimgl = {version = "^1.6.1", optional = true}
numpy = "^1.19"
opencv-python = "^4.6.0.66"
pydantic = "^1.10.2"
pyside6 = "^6.4.1"
python = ">=3.8.1,<3.12"
python-pptx = "^0.6.21"
requests = "^2.28.1"
rich = "^13.3.2"
tqdm = "^4.64.1"
[tool.poetry.extras]
manim = ["manim"]
manimgl = ["manimgl"]
[tool.poetry.group.dev.dependencies]
black = "^22.10.0"
bump2version = "^1.0.1"
isort = "^5.12.0"
mypy = "^0.991"
pre-commit = "^3.0.2"
ruff = "^0.0.219"
[tool.poetry.group.docs.dependencies]
furo = "^2022.9.29"
manim = "^0.17.0"
myst-parser = "^0.18.1"
sphinx = "^5.3.0"
sphinx-click = "^4.4.0"
sphinx-copybutton = "^0.5.1"
sphinxext-opengraph = "^0.7.5"
[tool.poetry.group.test.dependencies]
manim = "^0.17.0"
manimgl = "^1.6.1"
[tool.poetry.plugins]
[tool.poetry.plugins."console_scripts"]
manim-slides = "manim_slides.__main__:cli"
[tool.ruff]
ignore = [
"E501"
]
target-version = "py38"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

View File

@ -1,53 +0,0 @@
# flake8: noqa: F403, F405
# type: ignore
import os
from manim import *
THEME = os.environ.get("MANIM_SLIDES_THEME", "light").lower().replace("_", "-")
class ManimSlidesLogo(Scene):
def construct(self):
tex_template = TexTemplate()
tex_template.add_to_preamble(r"\usepackage{graphicx}\usepackage{fontawesome5}")
self.camera.background_color = {
"light": "#ffffff",
"dark-docs": "#131416",
"dark-github": "#0d1117",
}[THEME]
logo_green = "#87c2a5"
logo_blue = "#525893"
logo_red = "#e07a5f"
logo_black = {
"light": "#343434",
"dark-docs": "#d0d0d0",
"dark-github": "#c9d1d9",
}[THEME]
ds_m = MathTex(r"\mathbb{M}", fill_color=logo_black).scale(7)
ds_m.shift(2.25 * LEFT + 1.5 * UP)
slides = MathTex(r"\mathbb{S}\text{lides}", fill_color=logo_black).scale(4)
slides.next_to(ds_m, DOWN)
slides.shift(DOWN)
play = Tex(
r"\faStepBackward\faStepForward",
fill_color=logo_black,
tex_template=tex_template,
).scale(4)
play.next_to(ds_m, LEFT)
play.shift(LEFT + 0.5 * DOWN)
comment = Tex(
r"\reflectbox{\faComment*[regular]}",
fill_color=logo_black,
tex_template=tex_template,
).scale(9)
comment.move_to(play)
comment.shift(0.4 * DOWN)
circle = Circle(color=logo_green, fill_opacity=1).shift(LEFT)
square = Square(color=logo_blue, fill_opacity=1).shift(UP)
triangle = Triangle(color=logo_red, fill_opacity=1).shift(RIGHT)
logo = VGroup(
triangle, square, circle, ds_m, slides, comment, play
) # order matters
logo.move_to(ORIGIN)
self.add(logo)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

View File

@ -1,21 +0,0 @@
#! /bin/bash
MANIM_SLIDES_THEME=light poetry run manim render -qk -s --format png --resolution 2560,1280 static/logo.py && mv media/images/logo/*.png static/logo.png
ln -f -r -s static/logo.png docs/source/_static/logo.png
MANIM_SLIDES_THEME=dark_docs poetry run manim render -qk -s --format png --resolution 2560,1280 static/logo.py && mv media/images/logo/*.png static/logo_dark_docs.png
ln -f -r -s static/logo_dark_docs.png docs/source/_static/logo_dark_docs.png
MANIM_SLIDES_THEME=dark_github poetry run manim render -qk -s --format png --resolution 2560,1280 static/logo.py && mv media/images/logo/*.png static/logo_dark_github.png
ln -f -r -s static/logo_dark_github.png docs/source/_static/logo_dark_github.png
MANIM_SLIDES_THEME=light poetry run manim render -t -qk -s --format png --resolution 2560,1280 static/logo.py && mv media/images/logo/*.png static/logo_light_transparent.png
ln -f -r -s static/logo_light_transparent.png docs/source/_static/logo_light_transparent.png
MANIM_SLIDES_THEME=dark_docs poetry run manim render -t -qk -s --format png --resolution 2560,1280 static/logo.py && mv media/images/logo/*.png static/logo_dark_transparent.png
ln -f -r -s static/logo_dark_transparent.png docs/source/_static/logo_dark_transparent.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB