Manimを理解するlinter。壊れたレンダリングを、レンダリング前に。
Manimコードに対するRuffのようなフィードバックに、Scene.play、Mobjectの
ライフサイクル、updater、Cairo/OpenGL、毎フレームの描画コストへの理解を
加えた静的解析ツールです。ManimもSceneも実行せず、実行時エラー・気づきにくい
誤描画・性能問題を検出します。
uv tool install qual-manim
qual check .RuffやPyrightはPythonを検査し、QualはManimがそのコードをどう扱うかを検査します。
from manim import *
class Demo(Scene):
def construct(self):
square = Square()
tracker = ValueTracker(0)
label = always_redraw(
lambda: MathTex(f"x={tracker.get_value():.2f}")
)
self.add(square, label)
self.play(square.shift(RIGHT))
self.play(tracker.animate.set_value(8), run_time=8)$ qual check . --format concise
scene.py:9:21: MLP226 warning Each invocation constructs a `MathTex` and performs a cache-key lookup, and this f-string key varies per frame: every rendered frame can mint a distinct Text/TeX cache key and disk asset (`K_resource ≈ F`). Across the 1 play(s) where this callback provably executes it may create at least ~480 distinct keys.
scene.py:12:19: MLC102 error `square.shift(...)` mutates the mobject immediately and returns the mobject itself, not an Animation; use `.animate` (e.g. `square.animate.shift(...)`) inside `Scene.play()`.MLC102はレンダリングを中断させます。MLP226は毎フレーム異なるTeXアセットを
作る可能性があります。QualはManimのライフサイクルを追い、「一度だけ」と
「毎フレーム」を区別するため、両方を検出できます。フレーム数などの数値は、
ソースと選択したレンダープロファイルから証明できる場合だけ表示します。
Qual 0.3は、4ファミリーに分かれた92個の実装済みManim固有ルールを 提供します。
| ファミリー | 検出対象 |
|---|---|
| MLC — ライフサイクルと正しさ | 不正なAnimation、target/state不足、updater、同時書き込み、Scene所属の誤り |
| MLR — レンダリング | TeX、asset、geometry、描画順、camera、Cairo/OpenGL互換性による誤描画 |
| MLP — パフォーマンス | 毎フレームの構築、成長するScene graph、重いcallback、rasterやresource keyの乗数 |
| MLD — 決定性と可搬性 | FPS依存の動き、未seed乱数、platform path、font、frame callback内の外部状態 |
各診断はseverity(error / warning / info)とconfidence
(certain / high / medium / low)を分けて持ちます。静的に解決できない
挙動はUnknownにし、不確実性から高確度の警告を作りません。
PyPIパッケージはRust製ネイティブ実行ファイルをインストールします。利用時に Manim、LaTeX、Pythonランタイムは必要ありません。
# Pythonツールとして
uv tool install qual-manim
# または
pipx install qual-manim
# Rustツールとして(Rust 1.85以上)
cargo install qual --lockedLinux・macOS・Windows向けのstandalone installerとchecksum付きarchiveは、 各GitHub Releaseにあります。
# macOS / Linux
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/Poietra/qual/releases/latest/download/qual-installer.sh | shqual check . # richな端末表示
qual check . --format concise # 1診断1行
qual check . --format github # GitHub Actions annotation
qual check . --format sarif # SARIF 2.1.0
qual check . --fix # safe fixのみ
qual cost scenes/demo.py # Sceneごとの記号的コスト
qual coverage . # 解決できなかった解析範囲
qual explain MLC102 # 1ルールの完全な説明終了コードは、0が失敗閾値未満、1が閾値に達する診断あり、2が入力・設定・
内部エラーです。既存プロジェクトではbaselineを使って新規診断だけを検出できます。
qual check . --write-baseline .qual-baseline.json
qual check . --baseline .qual-baseline.json設定はpyproject.tomlの[tool.qual]に置きます。profileにrenderer、platform、
解像度、FPSを定義できます。詳細は
設定ガイドを参照してください。
ruff check .
pyright
qual check .- Ruff: style、import、Python一般のlint
- Pyright: Pythonの型
- Qual: Manimのライフサイクル、描画意味論、描画コスト
QualはRuff pluginではありません。Manim固有の問題は、複数文、helper、Scene所属、 Animationのsetup/cleanup、render profileをまたいで解析する必要があるため、独立した 解析器として動作します。
ドキュメントサイトでは次を横断検索できます。
- インストール、設定、CI、baseline、suppression、fix
- 92ルールすべての根拠とnear-miss
qual costとqual coverage- architecture、実測根拠、contributor向け資料
- versioned JSON contractとschema
公開される連携面はCLIとversioned JSONです。ネットワークAPIや公開Rust libraryでは ありません。
qual check . --format json
qual static-facts .
qual change-impact --before old-tree --after new-tree
qual source-bridge . --request request.json機械向けAPI概要から各RFCと JSON Schemaへ移動できます。
- Manim、plugin、解析対象コードをimport・実行しません。
- 現在のknowledge profileはManim Community 0.20を対象にします。
- asset検査はManimの探索順をモデル化し、lint実行環境のfilesystemを参照します。
- 動的Pythonは保守的に扱い、
qual coverageで未解決範囲を確認できます。 - Python一般のstyleや型エラーはRuff・Pyrightに任せます。
DESIGN.mdが意味モデル・ルールカタログ・公開contractの正典です。
CONTRIBUTING.mdにrepository構成、ルール追加、test gate、
knowledge profile更新手順があります。
cargo fmt --check
cargo test --all-features
cargo clippy --all-targets --all-features -- -D warningsQualはMIT Licenseで配布します。binary distributionに含まれる
LGPL対象依存関係についてはTHIRD-PARTY-LICENSES.mdと
RELINKING.mdを参照してください。
Qualは独立プロジェクトです。Manim CommunityとRuffは本プロジェクトに関与せず、 責任を負いません。