Skip to content

docs: add commit message format guide and commitizen pre-commit hook #4748

Description

@AleNunezArroyo

Describe the Feature / Proposal

Currently, development.md (recommends following Conventional Commits but only links to the generic specification, it does not define which types, scopes, or structure rules apply specifically to Manim.

I propose adding a dedicated Commit Message Format page to the contributing documentation, and a commitizen pre-commit hook to validate commit messages locally before they are recorded.


Proposed Changes

1. New documentation page: docs/source/contributing/commits.md

A detailed guide that customizes the Conventional Commits spec for Manim's architecture:

  • Allowed types: build | ci | docs | feat | fix | perf | refactor | test, each with Manim-specific descriptions and examples.
  • Allowed scopes: mobject | scene | animation | renderer | camera | cli | config | utils | docs | tests, mapped to their source folders (e.g. mobjectmanim/mobject/, configmanim/_config/).
  • Message structure: header (<type>(<scope>): <summary>), mandatory body (≥ 20 chars, except for docs type), optional footer for BREAKING CHANGE: / DEPRECATED: / issue references.
  • Revert format: revert: <original header> with SHA and reason in the body.
  • Concrete examples: simple fix, feature with body, docs change, refactor, breaking change, and revert.
Click to expand the proposed draft (commits.md)

Commit Message Format

We have precise rules over how our Git commit messages must be formatted.
This format leads to easier to read commit history and enables automated changelog generation and semantic versioning.

Each commit message consists of a header, a body, and a footer.

<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

The header is mandatory and must conform to the Commit Message Header format.

The body is mandatory for all commits except for those of type docs.
When the body is present it must be at least 20 characters long and must conform to the Commit Message Body format.

The footer is optional. The Commit Message Footer format describes what the footer is used for and the structure it must have.


Commit Message Header

<type>(<scope>): <short summary>
  │       │             │
  │       │             └─⫸ Summary in present tense. Not capitalized. No period at the end.
  │       │
  │       └─⫸ Commit Scope: mobject|scene|animation|renderer|camera|cli|config|utils|docs|tests
  │
  └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test

The <type> and <summary> fields are mandatory, the (<scope>) field is optional.

Summary

Use the summary field to provide a succinct description of the change:

  • Use the imperative, present tense: "change" not "changed" nor "changes"
  • Don't capitalize the first letter
  • No period (.) at the end

Type

Must be one of the following:

Type Description Manim Examples
build Changes that affect the build system or external dependencies pyproject.toml, dependency upgrades, hatchling build config
ci Changes to our CI configuration files and scripts GitHub Actions workflows, pre-commit configuration
docs Documentation-only changes Sphinx .rst guides, Markdown .md files, inline docstrings
feat A new feature A new geometric mobject, a new animation class, or a new CLI flag
fix A bug fix Fixing rendering crashes, coordinate misalignments, or type errors
perf A code change that improves performance Optimizing shader compilation, caching, or numpy operations
refactor A code change that neither fixes a bug nor adds a feature Decomposing large files, extracting helper classes
test Adding missing tests or correcting existing tests pytest modules, graphical output assertions, video regression tests

Scope

The scope should be the name of the module or architectural area affected by the change.

Scope Folder Description
mobject manim/mobject/ Mathematical Objects: shapes, text, images, graphs
scene manim/scene/ Scenes: animation lifecycle, construct(), timing
animation manim/animation/ Animations: drawing effects, transformations, speed modifiers
renderer manim/renderer/ Renderers: render loop, frame generation, Cairo/OpenGL backends
camera manim/camera/ Cameras: frame dimensions, zoom, panning, 3D perspectives
cli manim/cli/ CLI: argument parsing, subcommands, output formats
config manim/_config/ Configuration: global settings, manim.cfg, ManimConfig
utils manim/utils/ Utilities: colors, vectors, rate curves, Sphinx extensions
docs docs/ Documentation: Sphinx source, tutorials, translations
tests tests/ Test Suite: unit tests, graphical/video regression tests

Exceptions:

  • packaging: changes to Python packaging layout (e.g. pyproject.toml metadata, __init__.py exports)
  • changelog: updating release notes
  • none/empty: cross-cutting changes across multiple scopes

Commit Message Body

Use the imperative, present tense: "fix" not "fixed" nor "fixes".

Explain the motivation for the change. Include a comparison of previous vs. new behavior when it helps illustrate impact.


Commit Message Footer

The footer can contain information about breaking changes and deprecations, and references to GitHub issues or PRs.

BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
Fixes #<issue number>

Revert Commits

If the commit reverts a previous commit, begin with revert: , followed by the header of the reverted commit.

The body should contain:

  • This reverts commit <SHA>.
  • A clear description of the reason for reverting.

Examples

Simple fix:

fix(mobject): resolve vectorized fill opacity bug

Feature with body:

feat(animation): add staggered fade-in animation for submobjects

The existing FadeIn animation applies the effect to the entire mobject at once.
This new StaggeredFadeIn class applies a cascading delay to each submobject,
which is useful for animating grouped elements like matrix entries or graph nodes.

Closes #2145

Documentation change (body not required):

docs(config): add examples for ManimConfig programmatic usage

Breaking change:

feat(renderer): remove deprecated Cairo-only rendering path

BREAKING CHANGE: The `use_cairo_renderer` config flag has been removed.
All scenes now render through the unified pipeline. Users who relied on
Cairo-specific behavior should migrate to the OpenGL renderer or use
the compatibility shim documented in the migration guide.

Closes #1892

Revert:

revert: fix(mobject): resolve vectorized fill opacity bug

This reverts commit 21cf999abc123.

The original fix introduced a regression in 3D mobject rendering where
transparency values were incorrectly inherited by child submobjects.

2. Pre-commit hook: commitizen validation (.pre-commit-config.yaml)

Added commit-msg to default_stages and a new hook using commitizen-tools/commitizen v3.27.0 at the commit-msg stage:

-default_stages: [pre-commit, pre-push]
+default_stages: [pre-commit, pre-push, commit-msg]

+  - repo: https://github.com/commitizen-tools/commitizen
+    rev: v3.27.0
+    hooks:
+      - id: commitizen
+        stages: [commit-msg]

3. Commitizen configuration (pyproject.toml)

Added a [tool.commitizen] section with a regex pattern that strictly validates the allowed types and scopes:

+[tool.commitizen]
+name = "cz_conventional_commits"
+pattern = "^(?P<type>build|ci|docs|feat|fix|perf|refactor|test)..."
+schema_pattern = "^(build|ci|docs|feat|fix|perf|refactor|test)..."
+schema = "Example: fix(mobject): resolve vectorized fill opacity bug"

Why This Matters: Real Before & After Examples

To illustrate the impact, here is how some recent commits in the repository would look under the proposed guidelines:

Original Commit With Proposed Format What Changed
Fixed inconsistent stroke width
scaling for text in compound
objects (#4694)
fix(mobject): resolve inconsistent
stroke width scaling for text in
compound objects

Ensure stroke width scales
consistently for text inside compound
mobjects when the parent mobject
is resized.

Closes #4694
Added fix type and mobject scope. Changed past tense → present tense. Moved issue reference to footer. Added body with motivation.
Implement Mobject.always (#4594)
feat(mobject): implement always method

Add the always method to easily
register updater functions that
continuously run on the mobject.

Closes #4594
Added feat type and mobject scope. Lowercase summary. Added body explaining what the feature does.
Replace scipy.special.comb
with math.comb (#4598)
refactor(utils): replace
scipy.special.comb with math.comb
Added refactor type and utils scope (file: manim/utils/simple_functions.py). Lowercase, no PR number.
Update TinyTeX Windows/macOS
installation in `ci.yml` to fix
failing pipelines (#4679)
ci: update TinyTeX installation
on Windows and macOS
Changed to ci type (no scope needed, it's a workflow file). Clean, concise single-line header.
docs: improve TransformFromCopy
docstring (#4597)
docs(animation): improve
TransformFromCopy docstring
Added animation scope (file is in manim/animation/). Removed PR number. No body needed for docs.

Pattern: Most commits gain a clear type + scope, and get a lowercase imperative summary. Non-trivial fixes/features also get an explanatory body.


Benefits

  • Better onboarding: New contributors see exactly which type and scope to use instead of guessing from a generic spec.
  • Immediate local feedback: The commitizen hook rejects non-compliant messages at commit-msg stage, catching errors before CI.
  • Consistent history: Standardized format enables future automated changelog generation and semantic versioning.

If the proposal is accepted, I can submit a Pull Request that:

  1. Adds docs/source/contributing/commits.md
  2. Updates the reference in development.md
  3. Includes the .pre-commit-config.yaml and pyproject.toml changes shown above

Metadata

Metadata

Assignees

No one assigned

    Labels

    new featureEnhancement specifically adding a new feature (feature request should be used for issues instead)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions