Leaderboard github.com
3b1b/manim
Animation engine for explanatory math videos
AI provenance
2%
explicit
- Confidence
- 95%
- Coverage
- 100%
Estimated share of AI-generated code. Explicit attribution is a lower bound.
Code quality
66/100
adequate
- Confidence
- 90%
- Coverage
- 100%
Complexity, duplication, lint density, tests, CI, docs and review process.
Security
71/100
adequate
- Confidence
- 85%
- Coverage
- 100%
Secrets, static analysis, vulnerable dependencies, CI and supply-chain posture.
AI provenance
2% explicit
Explicit AI attribution on 2% of first-party code added; an estimated 2% including velocity signals.
How the score is built
- Explicitly attributed share2%
- Unattributed share in AI-pace bursts0%
- Estimated AI-generated share2%
- AI tool configuration files0
- Work sessions at AI pace0
- Releases at AI pace0
- Coding-style index (1.0+ means possible)0.04
Attributed AI tools
| Tool | Commits | Lines added | First seen | Last seen |
|---|---|---|---|---|
| Claude Code | 70 | 10,983 | 2026-08-03 | 2026-09-09 |
Lines added per month all AI-attributed share
- 2015-035,473 · 0% AI
- 2015-042,525 · 0% AI
- 2015-052,624 · 0% AI
- 2015-064,719 · 0% AI
- 2015-084,213 · 0% AI
- 2015-092,657 · 0% AI
- 2015-107,005 · 0% AI
- 2015-111,670 · 0% AI
- 2015-122,501 · 0% AI
- 2016-012,282 · 0% AI
- 2016-022,636 · 0% AI
- 2016-033,506 · 0% AI
- 2016-044,476 · 0% AI
- 2016-058,081 · 0% AI
- 2016-079,394 · 0% AI
- 2016-089,782 · 0% AI
- 2016-098,259 · 0% AI
- 2016-102,776 · 0% AI
- 2016-1110,403 · 0% AI
- 2016-125,092 · 0% AI
- 2017-019,999 · 0% AI
- 2017-029,243 · 0% AI
- 2017-0312,953 · 0% AI
- 2017-0415,356 · 0% AI
- 2017-0510,493 · 0% AI
- 2017-068,201 · 0% AI
- 2017-076,876 · 0% AI
- 2017-088,661 · 0% AI
- 2017-099,196 · 0% AI
- 2017-1010,048 · 0% AI
- 2017-112,627 · 0% AI
- 2017-127,620 · 0% AI
- 2018-0124,831 · 0% AI
- 2018-0217,786 · 0% AI
- 2018-0320,153 · 0% AI
- 2018-0420,518 · 0% AI
- 2018-0514,871 · 0% AI
- 2018-066,426 · 0% AI
- 2018-077,337 · 0% AI
- 2018-0812,662 · 0% AI
- 2018-092,484 · 0% AI
- 2018-101,271 · 0% AI
- 2018-116,495 · 0% AI
- 2018-123,295 · 0% AI
- 2019-018,983 · 0% AI
- 2019-0211,150 · 0% AI
- 2019-0310,624 · 0% AI
- 2019-046,574 · 0% AI
- 2019-053,236 · 0% AI
- 2019-0631,491 · 0% AI
- 2019-074,384 · 0% AI
- 2019-082,812 · 0% AI
- 2019-093,764 · 0% AI
- 2019-102,050 · 0% AI
- 2019-112,875 · 0% AI
- 2019-126,343 · 0% AI
- 2020-01218 · 0% AI
- 2020-026,120 · 0% AI
- 2020-0310,722 · 0% AI
- 2020-043,497 · 0% AI
- 2020-055,013 · 0% AI
- 2020-069,095 · 0% AI
- 2020-07207 · 0% AI
- 2020-0810,984 · 0% AI
- 2020-0939 · 0% AI
- 2020-103 · 0% AI
- 2020-11816 · 0% AI
- 2020-1210,252 · 0% AI
- 2021-015,222 · 0% AI
- 2021-022,142 · 0% AI
- 2021-03153 · 0% AI
- 2021-04111 · 0% AI
- 2021-051 · 0% AI
- 2021-06322 · 0% AI
- 2021-0778 · 0% AI
- 2021-08569 · 0% AI
- 2021-091,202 · 0% AI
- 2021-10299 · 0% AI
- 2021-111,889 · 0% AI
- 2021-12554 · 0% AI
- 2022-011,105 · 0% AI
- 2022-024,449 · 0% AI
- 2022-034,954 · 0% AI
- 2022-046,220 · 0% AI
- 2022-054,277 · 0% AI
- 2022-06257 · 0% AI
- 2022-0719 · 0% AI
- 2022-081,097 · 0% AI
- 2022-0966 · 0% AI
- 2022-101 · 0% AI
- 2022-11214 · 0% AI
- 2022-126,573 · 0% AI
- 2023-014,266 · 0% AI
- 2023-02737 · 0% AI
- 2023-0318 · 0% AI
- 2023-041 · 0% AI
- 2023-050 · 0% AI
- 2023-06140 · 0% AI
- 2023-0865 · 0% AI
- 2023-09128 · 0% AI
- 2023-101 · 0% AI
- 2023-1126 · 0% AI
- 2023-121 · 0% AI
- 2024-01149 · 0% AI
- 2024-02295 · 0% AI
- 2024-03439 · 0% AI
- 2024-041 · 0% AI
- 2024-052 · 0% AI
- 2024-066 · 0% AI
- 2024-0720 · 0% AI
- 2024-081,207 · 0% AI
- 2024-09282 · 0% AI
- 2024-10112 · 0% AI
- 2024-11492 · 0% AI
- 2024-123,022 · 0% AI
- 2025-011 · 0% AI
- 2025-0255 · 0% AI
- 2025-03106 · 0% AI
- 2025-06569 · 0% AI
- 2025-10224 · 0% AI
- 2026-02316 · 0% AI
- 2026-03157 · 0% AI
- 2026-07262 · 0% AI
- 2026-0810,555 · 96% AI
- 2026-09868 · 100% AI
Findings in AI-attributed lines vs the rest
From git blame: 4,446 lines trace to AI-attributed commits, 22,491 to others. Reported, not scored.
| Findings per 1,000 lines | AI-attributed | Other | Ratio |
|---|---|---|---|
| Code quality | 0.68 | 1.51 | 0.45× |
| Security | 0.00 | 0.62 | 0.00× |
Evidence by analyzer
Explicit AI attributionok26 items
- Claude Code: 70 attributed commits, 10,983 lines added
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-authored-by: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-authored-by: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- Claude Code: trailer 'Co-Authored-By: Claude'
- attributed_commit_share
- 1.2%
- attributed_commits
- 70
- attributed_loc
- 10,983
- attributed_loc_share
- 1.9%
- commits
- 5,603
- effective_loc
- 567,025
- tools_detected
- 1
AI tool configurationok
- artifacts
- 0
- tools_configured
- 0
- workflow_agents
- 0
Commit velocityok
- excluded_import_loc
- 22,262
- flagged_loc
- 0
- flagged_loc_share
- 0.0%
- flagged_units
- 0
- max_loc_per_hour
- 4,940.60
- measured_loc
- 544,763
- median_loc_per_hour
- 85.23
- pr_timed_units
- 116
- pre_ai_era_burst_loc
- 80,125
- pre_ai_era_bursts
- 18
- pre_ai_era_measured_loc
- 486,411
- work_units
- 2,232
Release velocityok
- flagged_releases
- 0
- max_loc_per_day
- 1,077.50
- releases
- 20
Coding styleok1 item
- count:assistant_voice
- 0
- count:emoji_in_code
- 0
- count:narrated_steps
- 1
- count:placeholder
- 0
- files:assistant_voice
- 0
- files:emoji_in_code
- 0
- files:narrated_steps
- 1
- files:placeholder
- 0
- index
- 0.04
- lines_scanned
- 26,937
- per_kloc:assistant_voice
- 0
- per_kloc:emoji_in_code
- 0
- per_kloc:narrated_steps
- 0.04
- per_kloc:placeholder
- 0
Findings in AI-written linesok
- ai_lines
- 4,446
- blame_failures
- 0
- files_blamed
- 108
- other_lines
- 22,491
- quality:ai_findings
- 3
- quality:ai_per_kloc
- 0.68
- quality:other_findings
- 34
- quality:other_per_kloc
- 1.51
- quality:ratio
- 0.45
- security:ai_findings
- 0
- security:ai_per_kloc
- 0
- security:other_findings
- 14
- security:other_per_kloc
- 0.62
- security:ratio
- 0
Code quality
66 adequate
Code quality is adequate: test-to-source ratio 0.05, no CI test run detected; 3% of function code in complex or long functions; 1% duplicated lines. Weakest area: testing.
How the score is built
- Complexity92
- Duplication93
- Lint and smells54
- Tests and CI40
- Documentation65
- Type safety40
- Review process75
Evidence by analyzer
Complexity (lizard)ok5 items
- on_key_press in manimlib/scene/interactive_scene.py: complexity 39, 57 lines
- parse in manimlib/mobject/svg/string_mobject.py: complexity 23, 101 lines
- dispatch in manimlib/event_handler/event_dispatcher.py: complexity 22, 37 lines
- show_function_graph in logo/logo.py: complexity 3, 128 lines
- parse_cli in manimlib/config.py: complexity 2, 179 lines
- complex_functions
- 3
- function_nloc
- 17,081
- functions
- 1,964
- long_functions
- 3
- many_param_functions
- 70
- mean_ccn
- 2.09
- p90_ccn
- 4
- risky_nloc_share
- 2.9%
Duplication (jscpd)ok10 items
- 6+ duplicated lines: docs/example.py:4 and example_scenes.py:651
- 6+ duplicated lines: manimlib/animation/fading.py:165 and manimlib/animation/fading.py:194
- 6+ duplicated lines: manimlib/mobject/boolean_ops.py:85 and manimlib/mobject/boolean_ops.py:108
- 6+ duplicated lines: manimlib/mobject/geometry.py:330 and manimlib/mobject/geometry.py:361
- 6+ duplicated lines: manimlib/mobject/geometry.py:401 and manimlib/mobject/mobject.py:1273
- 6+ duplicated lines: manimlib/mobject/interactive.py:99 and manimlib/mobject/interactive.py:140
- 6+ duplicated lines: manimlib/mobject/mobject.py:966 and manimlib/mobject/types/vectorized_mobject.py:1146
- 6+ duplicated lines: manimlib/mobject/mobject.py:1371 and manimlib/mobject/types/surface.py:471
- 6+ duplicated lines: manimlib/mobject/mobject.py:1808 and manimlib/mobject/numbers.py:152
- 6+ duplicated lines: manimlib/mobject/probability.py:162 and manimlib/mobject/probability.py:171
- compared_lines
- 20,013
- duplicated_lines
- 244
- duplicated_share
- 1.2%
- files
- 108
Lintok
- category:best-practice
- 6
- category:correctness
- 18
- category:maintainability
- 13
- findings
- 37
- scanned_lines
- 26,937
- weighted_findings
- 67
Tests and CIok2 items
- CI config: .github/workflows/docs.yml
.github/workflows/docs.yml - CI config: .github/workflows/publish.yml
.github/workflows/publish.yml
- check:ci_present
- yes
- check:ci_runs_lint
- no
- check:ci_runs_tests
- no
- check:has_tests
- yes
- check:test_ratio
- no
- check:tests_cochange
- no
- ci_files
- 2
- cochange_commits
- 264
- cochange_share
- 4.9%
- source_lines
- 26,937
- test_lines
- 1,461
- test_ratio
- 0.05
Documentationok2 items
- README.md
README.md - LICENSE.md
LICENSE.md
- check:changelog
- no
- check:contributing
- no
- check:license
- yes
- check:readme
- yes
- readme_lines
- 134
Type safetyok
- check:low_escape_density
- yes
- check:strict_config
- no
- escapes
- 78
- escapes_per_kloc
- 2.90
Security
71 adequate
Security posture is adequate: 8 high-severity SAST findings; 5 high-severity workflow issues. Weakest area: posture.
How the score is built
- Secrets100
- Static analysis (SAST)90
- Vulnerable dependencies100
- CI workflows33
- Security posture0
- OpenSSF Scorecard29
Evidence by analyzer
OpenSSF Scorecardok12 items
- Scorecard Maintained: 10/10 (18 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10)
- Scorecard Code-Review: 5/10 (Found 15/30 approved changesets -- score normalized to 5)
- Scorecard Dangerous-Workflow: 10/10 (no dangerous workflow patterns detected)
- Scorecard Token-Permissions: 0/10 (detected GitHub workflow tokens with excessive permissions)
- Scorecard Binary-Artifacts: 10/10 (no binaries found in the repo)
- Scorecard Pinned-Dependencies: 0/10 (dependency not pinned by hash detected -- score normalized to 0)
- Scorecard CII-Best-Practices: 0/10 (no effort to earn an OpenSSF best practices badge detected)
- Scorecard Security-Policy: 0/10 (security policy file not detected)
- Scorecard Fuzzing: 0/10 (project is not fuzzed)
- Scorecard License: 10/10 (license file detected)
- Scorecard Signed-Releases: 0/10 (Project has not signed or included provenance with any releases.)
- Scorecard SAST: 0/10 (SAST tool is not run on all commits -- score normalized to 0)
- aggregate
- 4.30
- check:Binary-Artifacts
- yes
- check:CII-Best-Practices
- no
- check:Code-Review
- yes
- check:Dangerous-Workflow
- yes
- check:Fuzzing
- no
- check:License
- yes
- check:Maintained
- yes
- check:Pinned-Dependencies
- no
- check:SAST
- no
- check:Security-Policy
- no
- check:Signed-Releases
- no
- check:Token-Permissions
- no
Package registriesok
- checked
- 35
- declared
- 35
- lookup_errors
- 0
- missing
- 0
- recent
- 0
Secrets (gitleaks)ok
- secrets_current
- 0
- secrets_history
- 0
- secrets_low_confidence
- 0
- secrets_nonprod
- 0
Static analysis (opengrep)ok
- findings
- 14
- findings_high
- 8
- findings_low
- 0
- findings_medium
- 6
- parse_errors
- 0
- scanned_lines
- 26,937
- weighted_findings
- 8.55
Dependencies (osv-scanner)ok
- penalty
- 0
- vulnerabilities
- 0
- vulnerable_packages
- 0
- vulns_critical
- 0
- vulns_high
- 0
- vulns_low
- 0
- vulns_medium
- 0
- vulns_unknown
- 0
CI workflows (zizmor)ok
- findings
- 10
- findings_high
- 5
- findings_low
- 2
- findings_medium
- 3
- penalty
- 66.30
- workflows
- 2
Security postureok
- check:dependency_updates
- no
- check:lockfiles
- yes
- check:security_policy
- no
- check:signed_commits
- no
- signed_commit_share
- 42.5%
- unpinned_manifests
- 0
Release downloadsok4 items
- release v1.7.0 ships manim-source-code.zip (160 downloads)
- release v1.6.1 ships manimgl-1.6.1-docs.zip (1741 downloads)
- release v1.6.0 ships manimgl-1.6.0-docs.zip (69 downloads)
- release v1.5.0 ships manimgl-1.5.0-docs.zip (141 downloads)
- binary_assets
- 4
- signals
- 1
- suspicious
- 0
Findings
28 high31 medium1 low1 info
| Severity | Rule | Location | Message | Tool |
|---|---|---|---|---|
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/animation/indication.py:316 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/animation/numbers.py:47 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/animation/numbers.py:62 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/animation/specialized.py:44 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/changing.py:121 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/changing.py:49 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/functions.py:105 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/interactive.py:325 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/number_line.py:294 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/number_line.py:302 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/number_line.py:303 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/svg/drawings.py:216 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/three_dimensions.py:383 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.correctness.return-in-init |
manimlib/mobject/vector_field.py:470 | `return` should never appear inside a class __init__ function. This will cause a runtime error. | Lint |
| high | opengrep/python.lang.best-practice.open-never-closed |
manimlib/scene/scene_file_writer.py:366 | file object opened without corresponding close | Lint |
| high | zizmor/unpinned-uses |
.github/workflows/docs.yml:18 | unpinned action reference [confidence high] | CI workflows (zizmor) |
| high | zizmor/unpinned-uses |
.github/workflows/docs.yml:21 | unpinned action reference [confidence high] | CI workflows (zizmor) |
| high | zizmor/unpinned-uses |
.github/workflows/docs.yml:37 | unpinned action reference [confidence high] | CI workflows (zizmor) |
| high | zizmor/unpinned-uses |
.github/workflows/publish.yml:17 | unpinned action reference [confidence high] | CI workflows (zizmor) |
| high | zizmor/unpinned-uses |
.github/workflows/publish.yml:20 | unpinned action reference [confidence high] | CI workflows (zizmor) |
| high | opengrep/python.lang.security.use-defused-xml |
manimlib/mobject/svg/svg_mobject.py:3 | The Python documentation recommends using `defusedxml` instead of `xml` because the native Python `xml` library is vulnerable to XML External Entity (XXE) attacks. These attacks can leak confidential data and "XML bombs" can cause... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit |
manimlib/scene/scene_file_writer.py:241 | Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit |
manimlib/scene/scene_file_writer.py:344 | Detected subprocess function 'call' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-spawn-process-audit |
manimlib/scene/scene_file_writer.py:378 | Found dynamic content when spawning a process. This is dangerous if external data can reach this function call because it allows a malicious actor to execute commands. Ensure no external data reaches here. [confidence low] | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit |
manimlib/scene/scene_file_writer.py:394 | Detected subprocess function 'call' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit |
manimlib/utils/sounds.py:26 | Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.subprocess-shell-true |
manimlib/utils/sounds.py:28 | Found 'subprocess' function 'Popen' with 'shell=True'. This is dangerous because this call will spawn the command using a shell process. Doing so propagates current shell settings and variables, which makes it much easier for a... | Static analysis (opengrep) |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit |
manimlib/utils/tex_file_writing.py:113 | Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external... | Static analysis (opengrep) |
| medium | opengrep/python.lang.best-practice.unspecified-open-encoding |
manimlib/config.py:338 | Missing 'encoding' parameter. 'open()' uses device locale encodings by default, corrupting files with special characters. Specify the encoding to ensure cross-platform support when opening files in text mode (e.g. encoding="utf-8"). | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/extract_scene.py:182 | Is "is_reload" a function or an attribute? If it is a function, you may have meant run_config.is_reload() because run_config.is_reload is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/mobject/mobject.py:2163 | Is "is_chaining" a function or an attribute? If it is a function, you may have meant self.is_chaining() because self.is_chaining is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/mobject/mobject.py:2173 | Is "is_chaining" a function or an attribute? If it is a function, you may have meant self.is_chaining() because self.is_chaining is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/mobject/mobject.py:2188 | Is "is_chaining" a function or an attribute? If it is a function, you may have meant self.is_chaining() because self.is_chaining is always true. | Lint |
| medium | opengrep/python.lang.best-practice.unspecified-open-encoding |
manimlib/renderer/shader_source.py:118 | Missing 'encoding' parameter. 'open()' uses device locale encodings by default, corrupting files with special characters. Specify the encoding to ensure cross-platform support when opening files in text mode (e.g. encoding="utf-8"). | Lint |
| medium | opengrep/python.lang.correctness.common-mistakes.string-concat-in-list |
manimlib/renderer/shader_source.py:93 | Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list? | Lint |
| medium | opengrep/python.lang.correctness.common-mistakes.string-concat-in-list |
manimlib/renderer/shader_source.py:96 | Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list? | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:124 | Is "is_selecting" a function or an attribute? If it is a function, you may have meant self.is_selecting() because self.is_selecting is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:125 | Is "is_grabbing" a function or an attribute? If it is a function, you may have meant self.is_grabbing() because self.is_grabbing is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:401 | Is "is_selecting" a function or an attribute? If it is a function, you may have meant self.is_selecting() because self.is_selecting is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:408 | Is "is_selecting" a function or an attribute? If it is a function, you may have meant self.is_selecting() because self.is_selecting is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:431 | Is "is_grabbing" a function or an attribute? If it is a function, you may have meant self.is_grabbing() because self.is_grabbing is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:547 | Is "is_grabbing" a function or an attribute? If it is a function, you may have meant self.is_grabbing() because self.is_grabbing is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/interactive_scene.py:610 | Is "is_grabbing" a function or an attribute? If it is a function, you may have meant self.is_grabbing() because self.is_grabbing is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/scene.py:722 | Is "is_closing" a function or an attribute? If it is a function, you may have meant self.window.is_closing() because self.window.is_closing is always true. | Lint |
| medium | opengrep/python.lang.maintainability.is-function-without-parentheses |
manimlib/scene/scene_embed.py:179 | Is "is_reload" a function or an attribute? If it is a function, you may have meant run_config.is_reload() because run_config.is_reload is always true. | Lint |
| medium | opengrep/python.lang.correctness.unchecked-subprocess-call |
manimlib/scene/scene_file_writer.py:344 | This is not checking the return value of this subprocess call; if it fails no exception will be raised. Consider subprocess.check_call() instead | Lint |
| medium | opengrep/python.lang.best-practice.unspecified-open-encoding |
manimlib/scene/scene_file_writer.py:366 | Missing 'encoding' parameter. 'open()' uses device locale encodings by default, corrupting files with special characters. Specify the encoding to ensure cross-platform support when opening files in text mode (e.g. encoding="utf-8"). | Lint |
| medium | opengrep/python.lang.best-practice.unspecified-open-encoding |
manimlib/scene/scene_file_writer.py:393 | Missing 'encoding' parameter. 'open()' uses device locale encodings by default, corrupting files with special characters. Specify the encoding to ensure cross-platform support when opening files in text mode (e.g. encoding="utf-8"). | Lint |
| medium | opengrep/python.lang.correctness.unchecked-subprocess-call |
manimlib/scene/scene_file_writer.py:394 | This is not checking the return value of this subprocess call; if it fails no exception will be raised. Consider subprocess.check_call() instead | Lint |
| medium | opengrep/python.lang.best-practice.unspecified-open-encoding |
manimlib/utils/svg_export.py:67 | Missing 'encoding' parameter. 'open()' uses device locale encodings by default, corrupting files with special characters. Specify the encoding to ensure cross-platform support when opening files in text mode (e.g. encoding="utf-8"). | Lint |
| medium | zizmor/excessive-permissions |
.github/workflows/docs.yml:12 | overly broad permissions [confidence medium] | CI workflows (zizmor) |
| medium | zizmor/artipacked |
.github/workflows/docs.yml:17 | credential persistence through GitHub Actions artifacts [confidence low] | CI workflows (zizmor) |
| medium | zizmor/excessive-permissions |
.github/workflows/publish.yml:8 | overly broad permissions [confidence medium] | CI workflows (zizmor) |
| medium | opengrep/python.lang.security.audit.exec-detected |
manimlib/extract_scene.py:178 | Detected the use of exec(). exec() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by... | Static analysis (opengrep) |
| medium | opengrep/python.lang.security.audit.exec-detected |
manimlib/extract_scene.py:24 | Detected the use of exec(). exec() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by... | Static analysis (opengrep) |
| medium | opengrep/python.lang.security.deserialization.avoid-pickle |
manimlib/mobject/mobject.py:635 | Avoid using `pickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar... | Static analysis (opengrep) |
| medium | opengrep/python.lang.security.deserialization.avoid-pickle |
manimlib/mobject/mobject.py:638 | Avoid using `pickle`, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar... | Static analysis (opengrep) |
| medium | opengrep/python.lang.security.audit.regex_dos |
manimlib/mobject/svg/text_mobject.py:232 | Detected usage of re.compile with an inefficient regular expression. This can lead to regular expression denial of service, which can result in service down time. Instead, check all regexes or use safer alternatives such as pyre2.... | Static analysis (opengrep) |
| medium | opengrep/python.lang.security.audit.dynamic-urllib-use-detected |
manimlib/utils/file_ops.py:41 | Detected a dynamic value being used with urllib. urllib supports 'file://' schemes, so a dynamic value controlled by a malicious actor may allow them to read arbitrary files. Audit uses of urllib calls to ensure user data cannot control... | Static analysis (opengrep) |
| low | zizmor/artipacked |
.github/workflows/publish.yml:17 | credential persistence through GitHub Actions artifacts [confidence low] | CI workflows (zizmor) |
| info | zizmor/use-trusted-publishing |
.github/workflows/publish.yml:37 | prefer trusted publishing for authentication [confidence high] | CI workflows (zizmor) |
Tools and coverage
Every analyzer that ran on this commit. A failed or skipped tool is a coverage gap: its share of the score is left out and the coverage figure drops.
| Analyzer | Pillar | Status | Version | Findings | Note |
|---|---|---|---|---|---|
| AI tool configuration | AI provenance | ok | signatures-v1 | 0 | |
| Explicit AI attribution | AI provenance | ok | signatures-v1 | 0 | |
| Release velocity | AI provenance | ok | prov-5 | 0 | |
| Coding style | AI provenance | ok | — | 0 | |
| Commit velocity | AI provenance | ok | prov-5 | 0 | |
| Findings in AI-written lines | AI provenance | ok | git-blame | 0 | |
| Complexity (lizard) | Code quality | ok | lizard 1.25.1 | 0 | |
| Documentation | Code quality | ok | — | 0 | |
| Duplication (jscpd) | Code quality | ok | repotrust-dup-w6 | 0 | |
| Lint | Code quality | ok | opengrep 1.33.1; rules f1d2b562b414 | 37 | |
| Tests and CI | Code quality | ok | — | 0 | |
| Type safety | Code quality | ok | — | 0 | |
| CI workflows (zizmor) | Security | ok | zizmor 1.32.0 | 10 | |
| Dependencies (osv-scanner) | Security | ok | osv-scanner version: 2.7.1 | 0 | |
| Release downloads | Security | ok | — | 0 | |
| Security posture | Security | ok | — | 0 | |
| Package registries | Security | ok | — | 0 | |
| Static analysis (opengrep) | Security | ok | opengrep 1.33.1; rules f1d2b562b414 | 14 | |
| OpenSSF Scorecard | Security | ok | scorecard v5.6.0 | 0 | |
| Secrets (gitleaks) | Security | ok | gitleaks 8.30.1 | 0 |
Score history
| Scored | Commit | Scoring | AI provenance | Quality | Security |
|---|---|---|---|---|---|
| 2026-11-14 | fafa083a4fb2 | prov-5+qual-2+sec-2 | 2% | 66 | 71 |
Full text report
- Repository: https://github.com/3b1b/manim
- Commit:
fafa083a4fb274bba9cabde0b6e2f50ba6da0622 - Generated: 2026-11-14T15:06:19+00:00
- Scorer 0.1.0, scoring prov-5+qual-2+sec-2, report schema v2
Scores
| Pillar | Score | Signal | Confidence | Coverage |
|---|---|---|---|---|
| AI provenance (estimated AI-generated share) | 2 | explicit | 95% | 100% |
| Code quality | 66 | adequate | 90% | 100% |
| Security | 71 | adequate | 85% | 100% |
AI provenance
Explicit AI attribution on 2% of first-party code added; an estimated 2% including velocity signals.
- Explicitly attributed share (lower bound): 1.9%
- Unattributed share in AI-consistent velocity bursts: 0.0%
- Estimated AI-generated share: 1.9%
| AI tool | Attributed commits | Lines added |
|---|---|---|
| Claude Code | 70 | 10,983 |
Current source lines last changed by AI-attributed commits: 4,446 of 26,937.
| Findings per 1,000 lines | AI-attributed | Other | Ratio |
|---|---|---|---|
| Quality | 0.675 | 1.512 | 0.45x |
| Security | 0.0 | 0.622 | 0.0x |
- Stylometry index: 0.04 per 1,000 lines (narrated steps 1, placeholders 0, assistant phrasing 0, emoji 0). Reported as a signal, not scored.
| Month | Lines added | Attributed to AI |
|---|---|---|
| 2024-11 | 492 | 0% |
| 2024-12 | 3,022 | 0% |
| 2025-01 | 1 | 0% |
| 2025-02 | 55 | 0% |
| 2025-03 | 106 | 0% |
| 2025-06 | 569 | 0% |
| 2025-10 | 224 | 0% |
| 2026-02 | 316 | 0% |
| 2026-03 | 157 | 0% |
| 2026-07 | 262 | 0% |
| 2026-08 | 10,555 | 96% |
| 2026-09 | 868 | 100% |
Evidence
- Claude Code: trailer 'Co-Authored-By: Claude' (fafa083a4fb2)
- Claude Code: trailer 'Co-authored-by: Claude' (013d97626c45)
- Claude Code: trailer 'Co-Authored-By: Claude' (31290eb25b2f)
- Claude Code: trailer 'Co-Authored-By: Claude' (1f105f90201a)
- Claude Code: trailer 'Co-authored-by: Claude' (53dcadca091e)
- Claude Code: trailer 'Co-Authored-By: Claude' (ef8e9b802f0b)
- Claude Code: trailer 'Co-Authored-By: Claude' (a58e6d38dc54)
- Claude Code: trailer 'Co-Authored-By: Claude' (bf78e8b94b6f)
- Claude Code: trailer 'Co-Authored-By: Claude' (8bd32c7aa6d4)
- Claude Code: trailer 'Co-Authored-By: Claude' (2c53c13a34b5)
- Claude Code: trailer 'Co-Authored-By: Claude' (024db54580e0)
- Claude Code: trailer 'Co-Authored-By: Claude' (d7726853edf6)
- Claude Code: trailer 'Co-Authored-By: Claude' (bfe798af299f)
- Claude Code: trailer 'Co-Authored-By: Claude' (793109b84ca7)
- Claude Code: trailer 'Co-Authored-By: Claude' (b409d777f782)
AI provenance describes how code was produced; it is not a quality judgment. Unless attribution is explicit, these are signals consistent with AI generation, not proof. Squash/rebase workflows, imported code, and rewritten history reduce accuracy.
Code quality
Code quality is adequate: test-to-source ratio 0.05, no CI test run detected; 3% of function code in complex or long functions; 1% duplicated lines. Weakest area: testing.
| Area | Score |
|---|---|
| Complexity (lizard) | 92 |
| Duplication | 93 |
| Code smells (Opengrep) | 54 |
| Tests and CI | 40 |
| Documentation | 65 |
| Type safety | 40 |
| Process (Scorecard review/maintenance) | 75 |
- Functions: 1,964; mean complexity 2.1, 90th percentile 4; 3 complex and 3 long functions
- Duplicated lines: 1.2% of 20,013 compared
- Tests: 1,461 test lines for 26,937 source lines (ratio 0.05); CI test commands: none detected; 5% of recent source commits also change tests
- Docs missing or thin: contributing, changelog
Most complex functions:
- on_key_press in manimlib/scene/interactive_scene.py: complexity 39, 57 lines
- parse in manimlib/mobject/svg/string_mobject.py: complexity 23, 101 lines
- dispatch in manimlib/event_handler/event_dispatcher.py: complexity 22, 37 lines
- show_function_graph in logo/logo.py: complexity 3, 128 lines
- parse_cli in manimlib/config.py: complexity 2, 179 lines
Security
Security posture is adequate: 8 high-severity SAST findings; 5 high-severity workflow issues. Weakest area: posture.
| Area | Score |
|---|---|
| Secrets (gitleaks, tree + history) | 100 |
| Static analysis (Opengrep) | 90 |
| Vulnerable dependencies (OSV) | 100 |
| CI workflows (zizmor) | 33 |
| Posture (policy, updates, signing, lockfiles) | 0 |
| OpenSSF Scorecard | 29 |
- Posture checks passed: lockfiles; missing: security policy, dependency updates, signed commits
- OpenSSF Scorecard aggregate: 4.3/10 (published 2026-11-09)
Top findings
| Severity | Finding | Location |
|---|---|---|
| high | opengrep/python.lang.security.use-defused-xml: The Python documentation recommends using defusedxml instead of xml because the native Python xml library is vulnerable to XML External Entity (XXE) attacks. These attacks can leak confidential data and "XML bombs" can cause denial of service. [confidence low] |
manimlib/mobject/svg/svg_mobject.py:3 |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit: Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low] |
manimlib/scene/scene_file_writer.py:241 |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit: Detected subprocess function 'call' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low] |
manimlib/scene/scene_file_writer.py:344 |
| high | opengrep/python.lang.security.audit.dangerous-spawn-process-audit: Found dynamic content when spawning a process. This is dangerous if external data can reach this function call because it allows a malicious actor to execute commands. Ensure no external data reaches here. [confidence low] |
manimlib/scene/scene_file_writer.py:378 |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit: Detected subprocess function 'call' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low] |
manimlib/scene/scene_file_writer.py:394 |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit: Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low] |
manimlib/utils/sounds.py:26 |
| high | opengrep/python.lang.security.audit.subprocess-shell-true: Found 'subprocess' function 'Popen' with 'shell=True'. This is dangerous because this call will spawn the command using a shell process. Doing so propagates current shell settings and variables, which makes it much easier for a malicious actor to execute commands. Use 'shell=False' instead. [confidence medium] |
manimlib/utils/sounds.py:28 |
| high | opengrep/python.lang.security.audit.dangerous-subprocess-use-audit: Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low] |
manimlib/utils/tex_file_writing.py:113 |
| high | zizmor/unpinned-uses: unpinned action reference [confidence high] |
.github/workflows/docs.yml:18 |
| high | zizmor/unpinned-uses: unpinned action reference [confidence high] |
.github/workflows/docs.yml:21 |
| high | zizmor/unpinned-uses: unpinned action reference [confidence high] |
.github/workflows/docs.yml:37 |
| high | zizmor/unpinned-uses: unpinned action reference [confidence high] |
.github/workflows/publish.yml:17 |
| high | zizmor/unpinned-uses: unpinned action reference [confidence high] |
.github/workflows/publish.yml:20 |
| medium | opengrep/python.lang.security.audit.exec-detected: Detected the use of exec(). exec() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by external sources. [confidence low] |
manimlib/extract_scene.py:24 |
| medium | opengrep/python.lang.security.audit.exec-detected: Detected the use of exec(). exec() can be dangerous if used to evaluate dynamic content. If this content can be input from outside the program, this may be a code injection vulnerability. Ensure evaluated content is not definable by external sources. [confidence low] |
manimlib/extract_scene.py:178 |
| medium | opengrep/python.lang.security.deserialization.avoid-pickle: Avoid using pickle, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format. [confidence low] |
manimlib/mobject/mobject.py:635 |
| medium | opengrep/python.lang.security.deserialization.avoid-pickle: Avoid using pickle, which is known to lead to code execution vulnerabilities. When unpickling, the serialized data could be manipulated to run arbitrary code. Instead, consider serializing the relevant data as JSON or a similar text-based serialization format. [confidence low] |
manimlib/mobject/mobject.py:638 |
| medium | opengrep/python.lang.security.audit.regex_dos: Detected usage of re.compile with an inefficient regular expression. This can lead to regular expression denial of service, which can result in service down time. Instead, check all regexes or use safer alternatives such as pyre2. [confidence low] |
manimlib/mobject/svg/text_mobject.py:232 |
| medium | opengrep/python.lang.security.audit.dynamic-urllib-use-detected: Detected a dynamic value being used with urllib. urllib supports 'file://' schemes, so a dynamic value controlled by a malicious actor may allow them to read arbitrary files. Audit uses of urllib calls to ensure user data cannot control the URLs, or consider using the 'requests' library instead. [confidence low] |
manimlib/utils/file_ops.py:41 |
| medium | zizmor/artipacked: credential persistence through GitHub Actions artifacts [confidence low] |
.github/workflows/docs.yml:17 |
| medium | zizmor/excessive-permissions: overly broad permissions [confidence medium] |
.github/workflows/docs.yml:12 |
| medium | zizmor/excessive-permissions: overly broad permissions [confidence medium] |
.github/workflows/publish.yml:8 |
| low | zizmor/artipacked: credential persistence through GitHub Actions artifacts [confidence low] |
.github/workflows/publish.yml:17 |
| info | zizmor/use-trusted-publishing: prefer trusted publishing for authentication [confidence high] |
.github/workflows/publish.yml:37 |
Static signals only: the scorer never runs the project's code. Secret findings are pattern matches that were not verified, and secret values are never stored.
Distribution signals
- binary-release-asset: release v1.7.0 ships manim-source-code.zip (160 downloads)
- binary-release-asset: release v1.6.1 ships manimgl-1.6.1-docs.zip (1741 downloads)
- binary-release-asset: release v1.6.0 ships manimgl-1.6.0-docs.zip (69 downloads)
- binary-release-asset: release v1.5.0 ships manimgl-1.5.0-docs.zip (141 downloads)
Signals consistent with a repository that exists to distribute a download. They are heuristics, not a verdict; release files were not downloaded or inspected.
Repository profile
- Source lines: 26,937; test lines: 1,461
| Language | Lines |
|---|---|
| Python | 28,398 |