Compare commits

...

268 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
bfad43bd38 chore(version): bump 4.13.0 to 4.13.1 2023-05-08 10:19:30 +02:00
6f2cbc9b19 fix(convert): --use-template fixed (#182)
As described in #181, there was a mismatch between the type return by `click` and the one used by `pydantic`. Now we only use `Path` types.

Closes #181
2023-05-08 10:18:57 +02:00
5bd88c2fd5 chore(version): bump 4.12.0 to 4.13.0 2023-05-07 23:24:01 +02:00
f0c17b1e2a chore(paper): update statement of need (#176)
* chore(paper): update statement of need

Closes #171

* chore(paper): making link more time-proof
2023-05-07 23:22:47 +02:00
fce9546a9b chore(ci/deps): publish wheels and add manim/manimgl as extras (#173)
* chore(deps): add manim and manimgl as extras

* chore(ci): publish wheels too

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

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

* chore(ci): run tests on dep. changes

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

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

* chore(ci): only use extras to build pages

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-07 23:01:59 +02:00
d6ad56120e chore(docs): update contributing guidelines (#177)
Add seeking for help and reporting an issue sections.

Closes #172
2023-05-07 23:01:44 +02:00
5db0261b01 chore(docs): update install documentation (#175)
* chore(docs): update install documentation

Closes #169

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

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

* chore(docs): update according to code quality report

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-07 23:01:32 +02:00
8ab33ef71f feat(cli): add more debugging messages (#180)
* feat(cli): add more debugging messages

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

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

* chore(lib): fix msg to be more correct

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

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

* chore(version): setup dummy version


chore(version): fix

* chore(ci): udpate version in __version__ too

* chore(version): revert changes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-04 10:54:24 +02:00
4da0e2cc2d [pre-commit.ci] pre-commit autoupdate (#178)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.262 → v0.0.263](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.262...v0.0.263)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-02 09:55:05 +02:00
0e82e28313 chore(ci): add action dependabot checks (#174)
Setup dependabot to check for new actions
2023-05-01 11:52:22 +02:00
8b13106fcc chore(paper): suggestions from JOSE review (#168)
* Suggestions for paper

* A  few suggestions for the documentation
2023-05-01 11:06:55 +02:00
bce4d8188f [pre-commit.ci] pre-commit autoupdate (#167)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.260 → v0.0.262](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.260...v0.0.262)
- [github.com/pre-commit/mirrors-mypy: v1.1.1 → v1.2.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.1.1...v1.2.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-04-27 00:00:14 +02:00
c420b47ad2 chore(version): bump 4.11.0 to 4.12.0 2023-04-07 10:42:57 +02:00
fad13f33dc [pre-commit.ci] pre-commit autoupdate (#166)
updates:
- [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.257 → v0.0.260](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.257...v0.0.260)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-04-07 10:40:04 +02:00
d42a7f5ff1 [pre-commit.ci] pre-commit autoupdate (#164)
updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.7.0 → v2.8.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.7.0...v2.8.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.255 → v0.0.257](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.255...v0.0.257)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-23 22:59:22 +01:00
88d598709a feat(cli/lib): use scene background color as default (#160)
* Use scene background color as default

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

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

* Minor changes to feature: Read scene background

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

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

* Small fix for feature "Read bg color"

* chore(ci): add typing ignore

* fix(ci): typo

---------

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-03-22 13:59:04 +01:00
2ba9b734a3 chore(version): bump 4.10.0 to 4.11.0 2023-03-20 16:32:24 +01:00
49c4a10453 fix(lib): prevent calling child method (#163)
Change `pause` to not call eventual child's `next_slide` method
2023-03-20 16:24:46 +01:00
8c578d2577 fix(cli): do not terminate slides early (#162)
* fix(cli): do not terminate slides early

When a slide is replayed (either normally or reversed), its state must be reset.

Closes #161

* [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-03-20 16:24:36 +01:00
2a327c470b feat(cli): auto detect resolution (#158)
* feat(cli): auto detect resolution

The `present` command will now read by default the resolution of each presentation, and only change it if specified by the user.

This PR also fixes bugs introduced by #156 and previous PRs, where the transition between two presentation was not correct...

* fix(lib): better to test if not None
2023-03-16 15:41:31 +01:00
04dcf530f5 [pre-commit.ci] pre-commit autoupdate (#157)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.254 → v0.0.255](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.254...v0.0.255)
- [github.com/pre-commit/mirrors-mypy: v1.0.1 → v1.1.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.1...v1.1.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-14 14:48:13 +01:00
9a573f29f1 feat(cli): add start at index options (#156)
* wip: start at index

* feat(cli): add start at index options

* fix(ci): correct callback

* chore(ci): fix type hint

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

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

* fix(cli): typo in variable name...

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-11 18:05:07 +01:00
02f425f536 feat(render): support skipping animations (#155)
* feat(render): support skipping animations

Manim Slides now supports when Manim or ManimGL skip rendering some animations. All non-public attributes or methods are now named with leading __

* [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-03-10 17:49:37 +01:00
149b12fd01 chore(lib): raise error if skipping
Temporary error before implementing this
2023-03-09 17:29:26 +01:00
e01be300a0 chore(version): bump 4.9.2 to 4.10.0 2023-03-09 14:16:43 +01:00
940916d4aa chore(lib): some fixes before new release 2023-03-09 14:06:02 +01:00
3da8fab145 chore(deps): remove pkg_resources in favor to importlib (#153)
* feat(convert): PowerPoint conversion 

You can now convert your presentations to PowerPoint

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

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

* chore(convert): autoplay media

* chore(deps): remove pkg_resources in favor to importlib

This is what pkg_resources' team recommends

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

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

* fix(deps): if case for Python 3.8 (<3.9)

* fix(convert): use correct pkg path

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

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

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

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

* fix(deps): remove duplicate deps

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

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

* fix(lib): add __init__.py

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-09 13:41:25 +01:00
f0c5d48107 feat(convert): PowerPoint conversion (#152)
* feat(convert): PowerPoint conversion 

You can now convert your presentations to PowerPoint

* fix(deps): push poetry lock

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

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

* fix(lint): ignore attr-defined because Windows-only

* chore(convert): autoplay media

* fix(convert): autoplay and autoloop

* chore(deps): update lock file

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

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

* feat(convert): use first frame as default poster frame

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

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

* chore(docs): document new feature

* [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-03-09 12:12:45 +01:00
426470ef3c chore(lib): use next_slide not pause (#151)
* chore(lib): use `next_slide` not `pause`

This deprecates `pause` function in favor to `next_slide`, that will also be called by `next_section` in the future.

* [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-03-08 16:57:10 +01:00
700584cbcc chore(lib): reduce import overhead (#147)
* chore(lib): reduce import overhead

This PR should reduce the import time overhead caused by manim imports. To solve this, manim is only imported when Slide or ThreeDSlide is needed. A custom logger is now defined, which copies the one from Manim Community. FFMPEG_BIN is now hardcoded, but should be configurable in the future via the CLI or some config file.

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

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

* fix(lib): remove last .manim import

* fix(lib): remove print

* chore(lib): fix typo

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-08 16:56:51 +01:00
a440da9468 [pre-commit.ci] pre-commit autoupdate (#148)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.253 → v0.0.254](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.253...v0.0.254)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-07 11:53:09 +01:00
6486ce147c fix(docs): small typo 2023-03-04 10:12:35 +01:00
b258deeb31 fix(style): no backstick 2023-03-03 23:01:02 +01:00
a32773c50f chore(docs): adding GUI and HTML documentation pages (#145)
* chore(docs): adding GUI and HTML documentation pages

As titled, this adds two pages to the docs

* fix(typo): languagetool suggestion
2023-03-03 21:56:00 +01:00
a16aa93ee6 chore(misc): JOSE paper (#144)
* chore(misc): JOSE paper

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

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

* fix(ci): update path

* fix(ci): tab error

* fix(ci): path to paper

* fix(paper): updates

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

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

* fix(paper): typos

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-03 16:34:35 +01:00
e809e64f9a fix(docs): typo in commands 2023-03-02 13:36:14 +01:00
5967760dc3 feat(cli): using cached files when possible (#142)
* feat(cli): using cached files when possible

This should improve a bit the overall performances

* [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-03-02 13:33:58 +01:00
7f824be682 chore(README): force links in badges 2023-03-02 13:32:57 +01:00
9346f199d7 chore(README): add docs badge and update wizard (#143) 2023-03-02 13:24:58 +01:00
5c40dc69d8 chore(docs): transparent logo and symbolic link (#141) 2023-03-02 12:47:42 +01:00
bf10068cfc [pre-commit.ci] pre-commit autoupdate (#140)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.249 → v0.0.253](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.249...v0.0.253)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-28 08:02:49 +01:00
2f307225d1 chore(ci): clear cache (#138)
* chore(ci): clear cache

We must force cache clearing to save a new media/ directory

* chore(ci): clear cache when PR is closed

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

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

* fix(ci): add write permission

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-27 11:24:50 +01:00
8b5db4b2fd chore(docs): add dark-themed logo (#137)
* chore(docs): add dark-themed logo

* fix(docs): swap themes
2023-02-26 12:29:43 +01:00
855c74de34 chore(version): bump 4.9.1 to 4.9.2 2023-02-26 00:17:12 +01:00
a70876d696 fix(convert): relative path in HTML files (#136)
This fixes an error introduced by #133
2023-02-26 00:11:12 +01:00
3cb0085f24 chore(version): bump 4.9.0 to 4.9.1 2023-02-25 17:41:09 +01:00
42d70380b0 chore(docs): add embed instructions (#135) 2023-02-25 17:29:42 +01:00
dc1be25e6e chore(lib): use pathlib.Path instead of str (#133)
* wip(lib): change os.path to pathlib.Path

* chore(lib): use pathlib.Path instead of str

* fix(logger): convert Path to str

* chore(lint): add type hint to prevent future errors

* fix(lib): correct suffix addition
2023-02-25 17:21:50 +01:00
4cd433b35a chore(docs): document sharing slides (#134)
* chore(docs): remove deprecated "last animation" mention

* chore(docs): document sharing slides
2023-02-25 13:30:12 +01:00
e83df48c5d chore(version): bump 4.8.4 to 4.9.0 2023-02-25 11:37:17 +01:00
ed30e2136a Add Feature BackgroundSize (#132) 2023-02-24 17:51:33 +01:00
a9f5355595 chore(deps): bump ipython from 8.9.0 to 8.10.0 (#126)
Bumps [ipython](https://github.com/ipython/ipython) from 8.9.0 to 8.10.0.
- [Release notes](https://github.com/ipython/ipython/releases)
- [Commits](https://github.com/ipython/ipython/compare/8.9.0...8.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-24 12:44:49 +01:00
1ef42ec82a chore(deps): bump markdown-it-py from 2.1.0 to 2.2.0 (#129)
Bumps [markdown-it-py](https://github.com/executablebooks/markdown-it-py) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/executablebooks/markdown-it-py/releases)
- [Changelog](https://github.com/executablebooks/markdown-it-py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/executablebooks/markdown-it-py/compare/v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: markdown-it-py
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-24 09:04:56 +01:00
b5f6a165db [pre-commit.ci] pre-commit autoupdate (#127)
updates:
- [github.com/macisamuele/language-formatters-pre-commit-hooks: v2.6.0 → v2.7.0](https://github.com/macisamuele/language-formatters-pre-commit-hooks/compare/v2.6.0...v2.7.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.243 → v0.0.249](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.243...v0.0.249)
- [github.com/pre-commit/mirrors-mypy: v0.991 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v0.991...v1.0.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-21 08:38:54 +01:00
7b9c9b0c39 fix(lib): a class can now have zero slide and work (#125)
* fix(lib): a class can now have zero slide and work

This fixes a previous issue that occured when a class didn't have any `pause`

* [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-02-08 18:58:54 +01:00
ac23949043 chore(version): bump 4.8.3 to 4.8.4 2023-02-08 11:01:38 +01:00
71564a4c2e fix(convert): use hash to restrict the length of new filenames (#124)
Closes #123
2023-02-08 11:00:53 +01:00
b06250056d [pre-commit.ci] pre-commit autoupdate (#121)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/psf/black: 22.12.0 → 23.1.0](https://github.com/psf/black/compare/22.12.0...23.1.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.237 → v0.0.243](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.237...v0.0.243)

* [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-02-08 09:32:03 +01:00
43c24d7ae1 fix(docs): update base site url 2023-02-01 11:47:02 +01:00
56 changed files with 4 additions and 7265 deletions

View File

@ -1,12 +0,0 @@
[bumpversion]
current_version = 4.8.3
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,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,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,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,81 +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:
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 Python dependencies
run: pip install manim sphinx sphinx_click furo
- name: Install local Python package
run: poetry install --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: 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,48 +0,0 @@
# Modified from: https://github.com/pypa/cibuildwheel
name: Upload Python Package
on:
push:
release:
types: [published]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- name: Install build package
run: python -m pip install -U build
- name: Build wheels
run: python -m build --sdist
- uses: actions/upload-artifact@v2
with:
name: dist
path: dist/*.tar.*
release:
name: Release
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
runs-on: ubuntu-latest
needs: [build_wheels]
steps:
- uses: actions/download-artifact@v2
with:
name: dist
path: dist/
- name: Upload to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

View File

@ -1,120 +0,0 @@
on:
pull_request:
paths:
- '**.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

37
.gitignore vendored
View File

@ -1,37 +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/

0
.nojekyll Normal file
View File

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.6.0
hooks:
- id: pretty-format-yaml
args: [--autofix]
- id: pretty-format-toml
exclude: poetry.lock
args: [--autofix]
- repo: https://github.com/psf/black
rev: 22.12.0
hooks:
- id: black
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.237
hooks:
- id: ruff
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.991
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.

188
README.md
View File

@ -1,186 +1,4 @@
![Manim Slides Logo](https://raw.githubusercontent.com/jeertmans/manim-slides/main/static/logo.png)
# GitHub Pages branch
[![Latest Release][pypi-version-badge]][pypi-version-url]
[![Python version][pypi-python-version-badge]][pypi-version-url]
![PyPI - Downloads](https://img.shields.io/pypi/dm/manim-slides)
# 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)
## 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
```
### 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.pause()` 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.pause() # 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.pause() # 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:
![manim-wizard](https://user-images.githubusercontent.com/27275099/197468787-19c83a81-d757-47b9-8f68-218427d30298.png)
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).
[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
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

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,65 +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",
]
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 = {
"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_use_first_image = True

View File

@ -1,21 +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.

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,57 +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 used 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
```
## 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 run
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,42 +0,0 @@
---
hide-toc: true
og:description: Manim Slides makes creating slides with Manim super easy!
---
```{eval-rst}
.. image:: _static/logo.png
:width: 600px
:align: center
: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
```
```{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 in 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, play
.. 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,17 +0,0 @@
# Reference Documentation
Automatically generated reference for Manim Slides.
```{toctree}
:hidden:
api
cli
examples
```
[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.

View File

@ -1,339 +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.pause() # 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.pause() # Waits user to press continue to go to the 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.pause()
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.pause()
square = Square()
self.play(Transform(dot, square))
self.pause()
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.pause()
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.pause()
self.play(FadeIn(step, shift=RIGHT))
self.play(Transform(code, code_step_1))
self.tinywait()
self.pause()
self.play(Transform(step, step_2))
self.play(Transform(code, code_step_2))
self.tinywait()
self.pause()
self.play(Transform(step, step_3))
self.play(Transform(code, code_step_3))
self.tinywait()
self.pause()
self.play(Transform(step, step_4))
self.play(Transform(code, code_step_4))
self.tinywait()
self.pause()
self.play(Transform(step, step_5))
self.play(Transform(code, code_step_5))
self.tinywait()
self.pause()
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.pause()
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.pause()
self.play(Rotate(square, angle=PI / 4))
self.tinywait()
self.pause()
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.pause()
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.pause()
self.play(dot.animate.move_to(RIGHT * 3))
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
# Each slide MUST end with an animation (a self.wait is considered an animation)
self.play(dot.animate.move_to(ORIGIN))
# [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.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=4, rate_func=linear)
self.end_loop()
frame.remove_updater(updater)
self.play(frame.animate.set_theta(30 * DEGREES))
self.play(dot.animate.move_to(ORIGIN))
self.pause()
self.play(dot.animate.move_to(RIGHT * 3))
self.pause()
self.start_loop()
self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)
self.end_loop()
# Each slide MUST end with an animation (a self.wait is considered an animation)
self.play(dot.animate.move_to(ORIGIN))
# [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,3 +0,0 @@
# flake8: noqa: F401
from .__version__ import __version__
from .slide import Slide, ThreeDSlide

View File

@ -1,73 +0,0 @@
import json
import click
import requests
from click_default_group import DefaultGroup
from . import __version__
from .convert import convert
from .manim import 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`.
"""
# 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.8.3"

View File

@ -1,82 +0,0 @@
from typing import Any, Callable
import click
from click import Context, Parameter
from .defaults import CONFIG_PATH, FOLDER_PATH
from .manim 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),
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(
["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),
help="Set slides folder.",
show_default=True,
)
return wrapper(function)

View File

@ -1,253 +0,0 @@
import os
import shutil
import subprocess
import tempfile
from enum import Enum
from typing import Callable, Dict, List, Optional, Set, Union
from pydantic import BaseModel, root_validator, validator
from PySide6.QtCore import Qt
from .manim import FFMPEG_BIN, logger
def merge_basenames(files: List[str]) -> str:
"""
Merge multiple filenames by concatenating basenames.
"""
dirname = os.path.dirname(files[0])
_, ext = os.path.splitext(files[0])
basename = "_".join(os.path.splitext(os.path.basename(file))[0] for file in files)
return os.path.join(dirname, 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[str]
@validator("files", pre=True, each_item=True)
def is_file_and_exists(cls, v: str) -> str:
if not os.path.exists(v):
raise ValueError(
f"Animation file {v} does not exist. Are you in the right directory?"
)
if not os.path.isfile(v):
raise ValueError(f"Animation file {v} is not a file")
return v
@root_validator
def animation_indices_match_files(
cls, values: Dict[str, Union[List[SlideConfig], List[str]]]
) -> Dict[str, Union[List[SlideConfig], List[str]]]:
files = values.get("files")
slides = values.get("slides")
if files is None or slides is None:
return values
n_files = len(files)
for slide in slides:
if slide.end_animation > n_files: # type: ignore
raise ValueError(
f"The following slide's contains animations not listed in files {files}: {slide}"
)
return values
def move_to(self, dest: str, copy: bool = True) -> "PresentationConfig":
"""
Moves (or copy) the files to a given directory.
"""
copy_func: Callable[[str, str], None] = shutil.copy
move_func: Callable[[str, str], None] = shutil.move
move = copy_func if copy else move_func
n = len(self.files)
for i in range(n):
file = self.files[i]
basename = os.path.basename(file)
dest_path = os.path.join(dest, basename)
logger.debug(f"Moving / copying {file} to {dest_path}")
move(file, dest_path)
self.files[i] = dest_path
return self
def concat_animations(self, dest: Optional[str] = None) -> "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]
if len(files) > 1:
dest_path = merge_basenames(files)
f = tempfile.NamedTemporaryFile(mode="w", delete=False)
f.writelines(f"file '{os.path.abspath(path)}'\n" for path in files)
f.close()
command = [
FFMPEG_BIN,
"-f",
"concat",
"-safe",
"0",
"-i",
f.name,
"-c",
"copy",
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())
dest_paths.append(dest_path)
else:
dest_paths.append(files[0])
slide_config.start_animation = i
slide_config.end_animation = i + 1
self.files = dest_paths
if dest:
return self.move_to(dest)
return self
DEFAULT_CONFIG = Config()

View File

@ -1,469 +0,0 @@
import os
import webbrowser
from enum import Enum
from typing import Any, Callable, Dict, Generator, List, Optional, Type, Union
import click
import pkg_resources
from click import Context, Parameter
from pydantic import BaseModel, PositiveInt, ValidationError
from .commons import folder_path_option, verbosity_option
from .config import PresentationConfig
from .present import get_scenes_presentation_config
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[str] = None
def convert_to(self, dest: str) -> 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: str) -> bool:
"""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,
}[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"
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_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) -> 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 = os.path.join(self.assets_dir, os.path.basename(file))
# 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-video="{file}" data-background-video-muted data-background-video-loop></section>'
else:
yield f'<section 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, str):
with open(self.template, "r") as f:
return f.read()
return pkg_resources.resource_string(
__name__, "data/revealjs_template.html"
).decode()
def open(self, file: str) -> bool:
return webbrowser.open(file)
def convert_to(self, dest: str) -> None:
"""Converts this configuration into a RevealJS HTML presentation, saved to DEST."""
dirname = os.path.dirname(dest)
basename, ext = os.path.splitext(os.path.basename(dest))
self.assets_dir = self.assets_dir.format(
dirname=dirname, basename=basename, ext=ext
)
full_assets_dir = os.path.join(dirname, self.assets_dir)
os.makedirs(full_assets_dir, exist_ok=True)
for presentation_config in self.presentation_configs:
presentation_config.concat_animations().move_to(full_assets_dir)
with open(dest, "w") as f:
sections = "".join(self.get_sections_iter())
revealjs_template = self.load_template()
content = revealjs_template.format(sections=sections, **self.dict())
f.write(content)
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(
"--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(
"--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")
@click.option(
"--to",
type=click.Choice(["html"], 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),
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: str,
dest: str,
to: str,
open_result: bool,
force: bool,
config_options: Dict[str, str],
template: Optional[str],
) -> 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,2 +0,0 @@
FOLDER_PATH: str = "./slides"
CONFIG_PATH: str = ".manim-slides.json"

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

View File

@ -1,861 +0,0 @@
import os
import platform
import sys
import time
from enum import Enum, IntEnum, auto, unique
from typing import Any, Dict, List, Optional, Tuple, Union
import click
import cv2
import numpy as np
from pydantic import ValidationError
from PySide6.QtCore import Qt, QThread, Signal, Slot
from PySide6.QtGui import QCloseEvent, QIcon, QImage, QKeyEvent, QPixmap, QResizeEvent
from PySide6.QtWidgets import QApplication, QGridLayout, QLabel, QWidget
from tqdm import tqdm
from .commons import config_path_option, verbosity_option
from .config import DEFAULT_CONFIG, Config, PresentationConfig, SlideConfig
from .defaults import FOLDER_PATH
from .manim import logger
from .resources import * # noqa: F401, F403
os.environ.pop(
"QT_QPA_PLATFORM_PLUGIN_PATH", None
) # See why here: https://stackoverflow.com/a/67863156
WINDOW_NAME = "Manim Slides"
WINDOW_INFO_NAME = f"{WINDOW_NAME}: Info"
WINDOWS = platform.system() == "Windows"
class AspectRatio(Enum):
ignore = Qt.IgnoreAspectRatio
keep = Qt.KeepAspectRatio
auto = "auto"
ASPECT_RATIO_MODES = {
"ignore": AspectRatio.ignore,
"keep": AspectRatio.keep,
"auto": AspectRatio.auto,
}
RESIZE_MODES = {
"fast": Qt.FastTransformation,
"smooth": Qt.SmoothTransformation,
}
@unique
class State(IntEnum):
"""Represents all possible states of a slide presentation."""
PLAYING = auto()
PAUSED = auto()
WAIT = auto()
END = auto()
def __str__(self) -> str:
return self.name.capitalize()
def now() -> float:
"""Returns time.time() in seconds."""
return time.time()
class Presentation:
"""Creates presentation from a configuration object."""
def __init__(self, config: PresentationConfig) -> None:
self.slides: List[SlideConfig] = config.slides
self.files: List[str] = config.files
self.current_slide_index: int = 0
self.current_animation: int = self.current_slide.start_animation
self.current_file: str = ""
self.loaded_animation_cap: int = -1
self.cap = None # cap = cv2.VideoCapture
self.reverse: bool = False
self.reversed_animation: int = -1
self.lastframe: Optional[np.ndarray] = None
self.reset()
@property
def current_slide(self) -> SlideConfig:
"""Returns currently playing slide."""
return self.slides[self.current_slide_index]
@property
def first_slide(self) -> SlideConfig:
"""Returns first slide."""
return self.slides[0]
@property
def last_slide(self) -> SlideConfig:
"""Returns last slide."""
return self.slides[-1]
def release_cap(self) -> None:
"""Releases current Video Capture, if existing."""
if self.cap is not None:
self.cap.release()
self.loaded_animation_cap = -1
def load_animation_cap(self, animation: int) -> None:
"""Loads video file of given animation."""
# We must load a new VideoCapture file if:
if (self.loaded_animation_cap != animation) or (
self.reverse and self.reversed_animation != animation
): # cap already loaded
logger.debug(f"Loading new cap for animation #{animation}")
self.release_cap()
file: str = self.files[animation]
if self.reverse:
file = "{}_reversed{}".format(*os.path.splitext(file))
self.reversed_animation = animation
self.current_file = file
self.cap = cv2.VideoCapture(file)
self.loaded_animation_cap = animation
@property
def current_cap(self) -> cv2.VideoCapture:
"""Returns current VideoCapture object."""
self.load_animation_cap(self.current_animation)
return self.cap
def rewind_current_slide(self) -> None:
"""Rewinds current slide to first frame."""
logger.debug("Rewinding curring slide")
if self.reverse:
self.current_animation = self.current_slide.end_animation - 1
else:
self.current_animation = self.current_slide.start_animation
cap = self.current_cap
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
def cancel_reverse(self) -> None:
"""Cancels any effet produced by a reversed slide."""
if self.reverse:
logger.debug("Cancelling effects from previous 'reverse' action'")
self.reverse = False
self.reversed_animation = -1
self.release_cap()
def reverse_current_slide(self) -> None:
"""Reverses current slide."""
self.reverse = True
self.rewind_current_slide()
def load_next_slide(self) -> None:
"""Loads next slide."""
logger.debug("Loading next slide")
if self.reverse:
self.cancel_reverse()
self.rewind_current_slide()
elif self.current_slide.is_last():
self.current_slide.terminated = True
else:
self.current_slide_index = min(
len(self.slides) - 1, self.current_slide_index + 1
)
self.rewind_current_slide()
def load_previous_slide(self) -> None:
"""Loads previous slide."""
logger.debug("Loading previous slide")
self.cancel_reverse()
self.current_slide_index = max(0, self.current_slide_index - 1)
self.rewind_current_slide()
@property
def fps(self) -> int:
"""Returns the number of frames per second of the current video."""
fps = self.current_cap.get(cv2.CAP_PROP_FPS)
if fps == 0:
logger.warn(
f"Something is wrong with video file {self.current_file}, as the fps returned by frame {self.current_frame_number} is 0"
)
return max(fps, 1) # TODO: understand why we sometimes get 0 fps
def reset(self) -> None:
"""Rests current presentation."""
self.current_animation = 0
self.load_animation_cap(0)
self.current_slide_index = 0
self.slides[-1].terminated = False
def load_last_slide(self) -> None:
"""Loads last slide."""
self.current_slide_index = len(self.slides) - 2
assert (
self.current_slide_index >= 0
), "Slides should be at list of a least two elements"
self.current_animation = self.current_slide.start_animation
self.load_animation_cap(self.current_animation)
self.slides[-1].terminated = False
@property
def next_animation(self) -> int:
"""Returns the next animation."""
if self.reverse:
return self.current_animation - 1
else:
return self.current_animation + 1
@property
def is_last_animation(self) -> int:
"""Returns True if current animation is the last one of current slide."""
if self.reverse:
return self.current_animation == self.current_slide.start_animation
else:
return self.next_animation == self.current_slide.end_animation
@property
def current_frame_number(self) -> int:
"""Returns current frame number."""
return int(self.current_cap.get(cv2.CAP_PROP_POS_FRAMES))
def update_state(self, state: State) -> Tuple[np.ndarray, State]:
"""
Updates the current state given the previous one.
It does this by reading the video information and checking if the state is still correct.
It returns the frame to show (lastframe) and the new state.
"""
if state == State.PAUSED:
if self.lastframe is None:
_, self.lastframe = self.current_cap.read()
return self.lastframe, state
still_playing, frame = self.current_cap.read()
if still_playing:
self.lastframe = frame
elif state == state.WAIT or state == state.PAUSED: # type: ignore
return self.lastframe, state
elif self.current_slide.is_last() and self.current_slide.terminated:
return self.lastframe, State.END
else: # not still playing
if self.is_last_animation:
if self.current_slide.is_slide():
state = State.WAIT
elif self.current_slide.is_loop():
if self.reverse:
state = State.WAIT
else:
self.current_animation = self.current_slide.start_animation
state = State.PLAYING
self.rewind_current_slide()
elif self.current_slide.is_last():
self.current_slide.terminated = True
elif (
self.current_slide.is_last()
and self.current_slide.end_animation == self.current_animation
):
state = State.WAIT
else:
# Play next video!
self.current_animation = self.next_animation
self.load_animation_cap(self.current_animation)
# Reset video to position zero if it has been played before
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
return self.lastframe, state
class Display(QThread): # type: ignore
"""Displays one or more presentations one after each other."""
change_video_signal = Signal(np.ndarray)
change_info_signal = Signal(dict)
finished = Signal()
def __init__(
self,
presentations: List[PresentationConfig],
config: Config = DEFAULT_CONFIG,
start_paused: bool = False,
skip_all: bool = False,
record_to: Optional[str] = None,
exit_after_last_slide: bool = False,
) -> None:
super().__init__()
self.presentations = presentations
self.start_paused = start_paused
self.config = config
self.skip_all = skip_all
self.record_to = record_to
self.recordings: List[Tuple[str, int, int]] = []
self.state = State.PLAYING
self.lastframe: Optional[np.ndarray] = None
self.current_presentation_index = 0
self.run_flag = True
self.key = -1
self.exit_after_last_slide = exit_after_last_slide
@property
def current_presentation(self) -> Presentation:
"""Returns the current presentation."""
return self.presentations[self.current_presentation_index]
def run(self) -> None:
"""Runs a series of presentations until end or exit."""
while self.run_flag:
last_time = now()
self.lastframe, self.state = self.current_presentation.update_state(
self.state
)
if self.state == State.PLAYING or self.state == State.PAUSED:
if self.start_paused:
self.state = State.PAUSED
self.start_paused = False
if self.state == State.END:
if self.current_presentation_index == len(self.presentations) - 1:
if self.exit_after_last_slide:
self.run_flag = False
continue
else:
self.current_presentation_index += 1
self.state = State.PLAYING
self.handle_key()
self.show_video()
self.show_info()
lag = now() - last_time
sleep_time = 1 / self.current_presentation.fps
sleep_time = max(sleep_time - lag, 0)
time.sleep(sleep_time)
last_time = now()
self.current_presentation.release_cap()
if self.record_to is not None:
self.record_movie()
logger.debug("Closing video thread gracully and exiting")
self.finished.emit()
def record_movie(self) -> None:
logger.debug(
f"A total of {len(self.recordings)} frames will be saved to {self.record_to}"
)
file, frame_number, fps = self.recordings[0]
cap = cv2.VideoCapture(file)
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number - 1)
_, frame = cap.read()
w, h = frame.shape[:2]
fourcc = cv2.VideoWriter_fourcc(*"XVID")
out = cv2.VideoWriter(self.record_to, fourcc, fps, (h, w))
out.write(frame)
for _file, frame_number, _ in tqdm(
self.recordings[1:], desc="Creating recording file", leave=False
):
if file != _file:
cap.release()
file = _file
cap = cv2.VideoCapture(_file)
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number - 1)
_, frame = cap.read()
out.write(frame)
cap.release()
out.release()
def show_video(self) -> None:
"""Shows updated video."""
if self.record_to is not None:
pres = self.current_presentation
self.recordings.append(
(pres.current_file, pres.current_frame_number, pres.fps)
)
frame: np.ndarray = self.lastframe
self.change_video_signal.emit(frame)
def show_info(self) -> None:
"""Shows updated information about presentations."""
self.change_info_signal.emit(
{
"animation": self.current_presentation.current_animation,
"state": self.state,
"slide_index": self.current_presentation.current_slide.number,
"n_slides": len(self.current_presentation.slides),
"type": self.current_presentation.current_slide.type,
"scene_index": self.current_presentation_index + 1,
"n_scenes": len(self.presentations),
}
)
@Slot(int)
def set_key(self, key: int) -> None:
"""Sets the next key to be handled."""
self.key = key
def handle_key(self) -> None:
"""Handles key strokes."""
key = self.key
if self.config.QUIT.match(key):
self.run_flag = False
elif self.state == State.PLAYING and self.config.PLAY_PAUSE.match(key):
self.state = State.PAUSED
elif self.state == State.PAUSED and self.config.PLAY_PAUSE.match(key):
self.state = State.PLAYING
elif self.state == State.WAIT and (
self.config.CONTINUE.match(key) or self.config.PLAY_PAUSE.match(key)
):
self.current_presentation.load_next_slide()
self.state = State.PLAYING
elif (
self.state == State.PLAYING and self.config.CONTINUE.match(key)
) or self.skip_all:
self.current_presentation.load_next_slide()
elif self.config.BACK.match(key):
if self.current_presentation.current_slide_index == 0:
if self.current_presentation_index == 0:
self.current_presentation.load_previous_slide()
else:
self.current_presentation_index -= 1
self.current_presentation.load_last_slide()
self.state = State.PLAYING
else:
self.current_presentation.load_previous_slide()
self.state = State.PLAYING
elif self.config.REVERSE.match(key):
self.current_presentation.reverse_current_slide()
self.state = State.PLAYING
elif self.config.REWIND.match(key):
self.current_presentation.cancel_reverse()
self.current_presentation.rewind_current_slide()
self.state = State.PLAYING
self.key = -1 # No more key to be handled
def stop(self) -> None:
"""Stops current thread, without doing anything after."""
self.run_flag = False
self.wait()
class Info(QWidget): # type: ignore
def __init__(self) -> None:
super().__init__()
self.setWindowTitle(WINDOW_INFO_NAME)
self.layout = QGridLayout()
self.setLayout(self.layout)
self.animationLabel = QLabel()
self.stateLabel = QLabel()
self.slideLabel = QLabel()
self.typeLabel = QLabel()
self.sceneLabel = QLabel()
self.layout.addWidget(self.animationLabel, 0, 0, 1, 2)
self.layout.addWidget(self.stateLabel, 1, 0)
self.layout.addWidget(self.slideLabel, 1, 1)
self.layout.addWidget(self.typeLabel, 2, 0)
self.layout.addWidget(self.sceneLabel, 2, 1)
self.update_info({})
@Slot(dict)
def update_info(self, info: Dict[str, Union[str, int]]) -> None:
self.animationLabel.setText("Animation: {}".format(info.get("animation", "na")))
self.stateLabel.setText("State: {}".format(info.get("state", "unknown")))
self.slideLabel.setText(
"Slide: {}/{}".format(
info.get("slide_index", "na"), info.get("n_slides", "na")
)
)
self.typeLabel.setText("Slide Type: {}".format(info.get("type", "unknown")))
self.sceneLabel.setText(
"Scene: {}/{}".format(
info.get("scene_index", "na"), info.get("n_scenes", "na")
)
)
class InfoThread(QThread): # type: ignore
def __init__(self) -> None:
super().__init__()
self.dialog = Info()
self.run_flag = True
def start(self) -> None:
super().start()
self.dialog.show()
def stop(self) -> None:
self.dialog.deleteLater()
class App(QWidget): # type: ignore
send_key_signal = Signal(int)
def __init__(
self,
*args: Any,
config: Config = DEFAULT_CONFIG,
fullscreen: bool = False,
resolution: Tuple[int, int] = (1980, 1080),
hide_mouse: bool = False,
aspect_ratio: AspectRatio = AspectRatio.auto,
resize_mode: Qt.TransformationMode = Qt.SmoothTransformation,
background_color: str = "black",
**kwargs: Any,
):
super().__init__()
self.setWindowTitle(WINDOW_NAME)
self.icon = QIcon(":/icon.png")
self.setWindowIcon(self.icon)
self.display_width, self.display_height = resolution
self.aspect_ratio = aspect_ratio
self.resize_mode = resize_mode
self.hide_mouse = hide_mouse
self.config = config
if self.hide_mouse:
self.setCursor(Qt.BlankCursor)
self.label = QLabel(self)
if self.aspect_ratio == AspectRatio.auto:
self.label.setScaledContents(True)
self.label.setAlignment(Qt.AlignCenter)
self.label.resize(self.display_width, self.display_height)
self.label.setStyleSheet(f"background-color: {background_color}")
self.pixmap = QPixmap(self.width(), self.height())
self.label.setPixmap(self.pixmap)
self.label.setMinimumSize(1, 1)
# create the video capture thread
kwargs["config"] = config
self.thread = Display(*args, **kwargs)
# create the info dialog
self.info = Info()
self.info.show()
# info widget will also listen to key presses
self.info.keyPressEvent = self.keyPressEvent
if fullscreen:
self.showFullScreen()
# connect signals
self.thread.change_video_signal.connect(self.update_image)
self.thread.change_info_signal.connect(self.info.update_info)
self.thread.finished.connect(self.closeAll)
self.send_key_signal.connect(self.thread.set_key)
# start the thread
self.thread.start()
def keyPressEvent(self, event: QKeyEvent) -> None:
key = event.key()
if self.config.HIDE_MOUSE.match(key):
if self.hide_mouse:
self.setCursor(Qt.ArrowCursor)
self.hide_mouse = False
else:
self.setCursor(Qt.BlankCursor)
self.hide_mouse = True
# We send key to be handled by video display
self.send_key_signal.emit(key)
event.accept()
def closeAll(self) -> None:
logger.debug("Closing all QT windows")
self.thread.stop()
self.info.deleteLater()
self.deleteLater()
def resizeEvent(self, event: QResizeEvent) -> None:
if not self.label.hasScaledContents():
self.pixmap = self.pixmap.scaled(
self.width(), self.height(), self.aspect_ratio.value, self.resize_mode
)
self.label.setPixmap(self.pixmap)
self.label.resize(self.width(), self.height())
def closeEvent(self, event: QCloseEvent) -> None:
self.closeAll()
event.accept()
@Slot(np.ndarray)
def update_image(self, cv_img: np.ndarray) -> None:
"""Updates the (image) label with a new opencv image"""
h, w, ch = cv_img.shape
bytes_per_line = ch * w
qt_img = QImage(cv_img.data, w, h, bytes_per_line, QImage.Format_BGR888)
if not self.label.hasScaledContents() and (
w != self.width() or h != self.height()
):
qt_img = qt_img.scaled(
self.width(), self.height(), self.aspect_ratio.value, self.resize_mode
)
self.label.setPixmap(QPixmap.fromImage(qt_img))
@click.command()
@click.option(
"--folder",
metavar="DIRECTORY",
default=FOLDER_PATH,
type=click.Path(exists=True, file_okay=False),
help="Set slides folder.",
show_default=True,
)
@click.help_option("-h", "--help")
@verbosity_option
def list_scenes(folder: str) -> None:
"""List available scenes."""
for i, scene in enumerate(_list_scenes(folder), start=1):
click.secho(f"{i}: {scene}", fg="green")
def _list_scenes(folder: str) -> List[str]:
"""Lists available scenes in given directory."""
scenes = []
for file in os.listdir(folder):
if file.endswith(".json"):
filepath = os.path.join(folder, file)
try:
_ = PresentationConfig.parse_file(filepath)
scenes.append(os.path.basename(file)[:-5])
except Exception as e: # Could not parse this file as a proper presentation config
logger.warn(
f"Something went wrong with parsing presentation config `{filepath}`: {e}"
)
pass
logger.debug(f"Found {len(scenes)} valid scene configuration files in `{folder}`.")
return scenes
def prompt_for_scenes(folder: str) -> List[str]:
"""Prompts the user to select scenes within a given folder."""
scene_choices = dict(enumerate(_list_scenes(folder), start=1))
for i, scene in scene_choices.items():
click.secho(f"{i}: {scene}", fg="green")
click.echo()
click.echo("Choose number corresponding to desired scene/arguments.")
click.echo("(Use comma separated list for multiple entries)")
def value_proc(value: Optional[str]) -> List[str]:
indices = list(map(int, (value or "").strip().replace(" ", "").split(",")))
if not all(0 < i <= len(scene_choices) for i in indices):
raise click.UsageError("Please only enter numbers displayed on the screen.")
return [scene_choices[i] for i in indices]
if len(scene_choices) == 0:
raise click.UsageError(
"No scenes were found, are you in the correct directory?"
)
while True:
try:
scenes = click.prompt("Choice(s)", value_proc=value_proc)
return scenes
except ValueError as e:
raise click.UsageError(str(e))
def get_scenes_presentation_config(
scenes: List[str], folder: str
) -> List[PresentationConfig]:
"""Returns a list of presentation configurations based on the user input."""
if len(scenes) == 0:
scenes = prompt_for_scenes(folder)
presentation_configs = []
for scene in scenes:
config_file = os.path.join(folder, f"{scene}.json")
if not os.path.exists(config_file):
raise click.UsageError(
f"File {config_file} does not exist, check the scene name and make sure to use Slide as your scene base class"
)
try:
presentation_configs.append(PresentationConfig.parse_file(config_file))
except ValidationError as e:
raise click.UsageError(str(e))
return presentation_configs
@click.command()
@click.argument("scenes", nargs=-1)
@config_path_option
@click.option(
"--folder",
metavar="DIRECTORY",
default=FOLDER_PATH,
type=click.Path(exists=True, file_okay=False),
help="Set slides folder.",
show_default=True,
)
@click.option("--start-paused", is_flag=True, help="Start paused.")
@click.option("--fullscreen", is_flag=True, help="Fullscreen mode.")
@click.option(
"-s",
"--skip-all",
is_flag=True,
help="Skip all slides, useful the test if slides are working. Automatically sets `--skip-after-last-slide` to True.",
)
@click.option(
"-r",
"--resolution",
metavar="<WIDTH HEIGHT>",
type=(int, int),
default=(1920, 1080),
help="Window resolution WIDTH HEIGHT used if fullscreen is not set. You may manually resize the window afterward.",
show_default=True,
)
@click.option(
"--to",
"--record-to",
"record_to",
metavar="FILE",
type=click.Path(dir_okay=False),
default=None,
help="If set, the presentation will be recorded into a AVI video file with given name.",
)
@click.option(
"--exit-after-last-slide",
is_flag=True,
help="At the end of last slide, the application will be exited.",
)
@click.option(
"--hide-mouse",
is_flag=True,
help="Hide mouse cursor.",
)
@click.option(
"--aspect-ratio",
type=click.Choice(ASPECT_RATIO_MODES.keys(), case_sensitive=False),
default="auto",
help="Set the aspect ratio mode to be used when rescaling video. `'auto'` option is equivalent to `'ignore'`, but can be much faster due to not calling `scaled()` method on every frame.",
show_default=True,
)
@click.option(
"--resize-mode",
type=click.Choice(RESIZE_MODES.keys(), case_sensitive=False),
default="smooth",
help="Set the resize (i.e., transformation) mode to be used when rescaling video.",
show_default=True,
)
@click.option(
"--background-color",
"--bgcolor",
"background_color",
metavar="COLOR",
type=str,
default="black",
help='Set the background color for borders when using "keep" resize mode. Can be any valid CSS color, e.g., "green", "#FF6500" or "rgba(255, 255, 0, .5)".',
show_default=True,
)
@click.help_option("-h", "--help")
@verbosity_option
def present(
scenes: List[str],
config_path: str,
folder: str,
start_paused: bool,
fullscreen: bool,
skip_all: bool,
resolution: Tuple[int, int],
record_to: Optional[str],
exit_after_last_slide: bool,
hide_mouse: bool,
aspect_ratio: str,
resize_mode: str,
background_color: str,
) -> None:
"""
Present SCENE(s), one at a time, in order.
Each SCENE parameter must be the name of a Manim scene, with existing SCENE.json config file.
You can present the same SCENE multiple times by repeating the parameter.
Use `manim-slide list-scenes` to list all available scenes in a given folder.
"""
if skip_all:
exit_after_last_slide = True
presentations = [
Presentation(presentation_config)
for presentation_config in get_scenes_presentation_config(scenes, folder)
]
if os.path.exists(config_path):
try:
config = Config.parse_file(config_path)
except ValidationError as e:
raise click.UsageError(str(e))
else:
logger.debug("No configuration file found, using default configuration.")
config = Config()
if record_to is not None:
_, ext = os.path.splitext(record_to)
if ext.lower() != ".avi":
raise click.UsageError(
"Recording only support '.avi' extension. For other video formats, please convert the resulting '.avi' file afterwards."
)
app = QApplication(sys.argv)
app.setApplicationName("Manim Slides")
a = App(
presentations,
config=config,
start_paused=start_paused,
fullscreen=fullscreen,
skip_all=skip_all,
resolution=resolution,
record_to=record_to,
exit_after_last_slide=exit_after_last_slide,
hide_mouse=hide_mouse,
aspect_ratio=ASPECT_RATIO_MODES[aspect_ratio],
resize_mode=RESIZE_MODES[resize_mode],
background_color=background_color,
)
a.show()
sys.exit(app.exec_())

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,237 +0,0 @@
import os
import platform
import shutil
import subprocess
from typing import Any, List, Optional
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 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(
self.file_writer.partial_movie_directory, **kwargs
)
else:
return self.renderer.file_writer.partial_movie_files
@property
def show_progress_bar(self) -> bool:
"""Returns True if progress bar should be displayed."""
if MANIMGL:
return getattr(super(Scene, self), "show_progress_bar", True)
else:
return config["progress_bar"] != "none"
@property
def leave_progress_bar(self) -> bool:
"""Returns True if progress bar should be left after completed."""
if MANIMGL:
return getattr(super(Scene, self), "leave_progress_bars", False)
else:
return config["progress_bar"] == "leave"
def play(self, *args: Any, **kwargs: Any) -> None:
"""Overloads `self.play` and increment animation count."""
super().play(*args, **kwargs)
self.current_animation += 1
def pause(self) -> None:
"""Creates a new slide with previous animations."""
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 add_last_slide(self) -> None:
"""Adds a 'last' slide to the end of slides."""
if 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."""
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."""
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 = type(self).__name__
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,
):
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)
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).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 intermidiate 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,196 +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 .manim 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}`")

2859
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,107 +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]
check-untyped-defs = true
# Disallow dynamic typing
disallow-any-generics = true
disallow-incomplete-defs = true
disallow-subclassing-any = true
# Disallow untyped definitions and calls
disallow-untyped-defs = true
ignore-missing-imports = true
install-types = true
# None and optional handling
no-implicit-optional = true
no-warn-return-any = true
non-interactive = true
python_version = "3.8"
# Strict equality
strict-equality = true
warn-no-return = true
warn-redundant-casts = true
# Config file
warn-unused-configs = true
# Configuring warnings
warn-unused-ignores = 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.8.3"
[tool.poetry.dependencies]
click = "^8.1.3"
click-default-group = "^1.2.2"
numpy = "^1.19"
opencv-python = "^4.6.0.66"
pydantic = "^1.10.2"
pyside6 = "^6.4.1"
python = ">=3.8.1,<3.12"
requests = "^2.28.1"
tqdm = "^4.64.1"
[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,41 +0,0 @@
# flake8: noqa: F403, F405
# type: ignore
from manim import *
class ManimSlidesLogo(Scene):
def construct(self):
tex_template = TexTemplate()
tex_template.add_to_preamble(r"\usepackage{graphicx}\usepackage{fontawesome5}")
self.camera.background_color = "#ffffff"
logo_green = "#87c2a5"
logo_blue = "#525893"
logo_red = "#e07a5f"
logo_black = "#343434"
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: 35 KiB