Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/docspublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ jobs:
run: |
uv --version
uv sync --frozen --group base --group script
- name: Install VHS
uses: charmbracelet/vhs-action@v2
- name: Update CLI screenshots
run: |
uv run --no-sync poe doc:screenshots
- name: Commit and push updated CLI screenshots
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add docs/images/cli_help
git add docs/images/cli_help docs/images/*.gif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can put all files generated by the command in a dedicated folder.

if [[ -n "$(git status --porcelain)" ]]; then
git commit -m "docs(cli/screenshots): update CLI screenshots" -m "[skip ci]"
Expand Down
Binary file added docs/images/commit.gif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Please replace all occurrences of demo.gif in the docs with this and remove demo.gif.
  2. Maybe put all vhs generated file under some dedicated folder, for example, docs/images/vhs/, and put all *.tape files outside images/ directory since they are just data for generating the .gif files.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
133 changes: 133 additions & 0 deletions docs/images/commit.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# VHS documentation https://github.com/charmbracelet/vhs
#
# Output:
# Output <path>.gif Create a GIF output at the given <path>

#
# Settings:
# Set FontSize <number> Set the font size of the terminal
# Set FontFamily <string> Set the font family of the terminal
# Set Height <number> Set the height of the terminal
# Set Width <number> Set the width of the terminal
# Set LetterSpacing <float> Set the letter spacing of the terminal
# Set LineHeight <float> Set the line height of the terminal
# Set Theme <json|string> Set the theme of the terminal
# Set Padding <number> Set the padding of the terminal
# Set TypingSpeed <time> Set the typing speed of the terminal

Comment on lines +1 to +17
Copy link
Collaborator

@bearomorphism bearomorphism Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need these comments?

Output commit.gif

Require cz

# Use bash for cross-platform compatibility (macOS, Linux, Windows)
Set Shell bash

Set FontSize 16
Set Width 878
Set Height 568
Set Padding 20
Set TypingSpeed 50ms

Set Theme {
"name": "Commitizen",
"black": "#232628",
"red": "#fc4384",
"green": "#b3e33b",
"yellow": "#ffa727",
"blue": "#75dff2",
"magenta": "#ae89fe",
"cyan": "#708387",
"white": "#d5d5d0",
"brightBlack": "#626566",
"brightRed": "#ff7fac",
"brightGreen": "#c8ed71",
"brightYellow": "#ebdf86",
"brightBlue": "#75dff2",
"brightMagenta": "#ae89fe",
"brightCyan": "#b1c6ca",
"brightWhite": "#f9f9f4",
"background": "#1e1e2e",
"foreground": "#afafaf",
"cursor": "#c7c7c7"
}

# Hide initial shell prompt
Hide

# Wait for terminal to be ready
Sleep 1s

# Set a clean, simple prompt (while hidden)
Type "PS1='$ '"
Enter
Sleep 300ms

# Create a clean temporary directory for recording
Type "rm -rf /tmp/commitizen-demo && mkdir -p /tmp/commitizen-demo && cd /tmp/commitizen-demo"
Enter
Sleep 500ms

# Initialize git repository
Type "git init"
Enter
Sleep 500ms

Type "git checkout -b awesome-feature"
Enter
Sleep 500ms

# Create a dummy file to commit
Type "echo 'test content' > example.py"
Enter
Sleep 300ms

Type "git add example.py"
Enter
Sleep 300ms

# Clear the screen to start fresh
Type "clear"
Enter
Sleep 500ms

# Show commands from here
Show

# Now run cz commit
Type "cz commit"
Sleep 500ms
Enter

# Wait for first prompt to appear
Sleep 1s

# Question 1: Select the type of change (move down to "feat")
Down
Sleep 500ms
Enter
Sleep 1s

# Question 2: Scope (optional, skip)
Enter
Sleep 1s

# Question 3: Subject
Type "awesome new feature"
Sleep 500ms
Enter
Sleep 1s

# Question 4: Is this a BREAKING CHANGE? (No)
Enter
Sleep 1s

# Question 5: Body (optional, skip)
Enter
Sleep 1s

# Question 6: Footer (optional, skip)
Enter
Sleep 1s

# Wait for commit success message
Sleep 2s
Binary file modified docs/images/init.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions docs/images/init.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# VHS documentation https://github.com/charmbracelet/vhs
#
# Output:
# Output <path>.gif Create a GIF output at the given <path>

#
# Settings:
# Set FontSize <number> Set the font size of the terminal
# Set FontFamily <string> Set the font family of the terminal
# Set Height <number> Set the height of the terminal
# Set Width <number> Set the width of the terminal
# Set LetterSpacing <float> Set the letter spacing of the terminal
# Set LineHeight <float> Set the line height of the terminal
# Set Theme <json|string> Set the theme of the terminal
# Set Padding <number> Set the padding of the terminal
# Set TypingSpeed <time> Set the typing speed of the terminal

Comment on lines +1 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Output init.gif

Require cz

# Use bash for cross-platform compatibility (macOS, Linux, Windows)
Set Shell bash

Set FontSize 16
Set Width 878
Set Height 568
Set Padding 20
Set TypingSpeed 50ms

Set Theme {
"name": "Commitizen",
"black": "#232628",
"red": "#fc4384",
"green": "#b3e33b",
"yellow": "#ffa727",
"blue": "#75dff2",
"magenta": "#ae89fe",
"cyan": "#708387",
"white": "#d5d5d0",
"brightBlack": "#626566",
"brightRed": "#ff7fac",
"brightGreen": "#c8ed71",
"brightYellow": "#ebdf86",
"brightBlue": "#75dff2",
"brightMagenta": "#ae89fe",
"brightCyan": "#b1c6ca",
"brightWhite": "#f9f9f4",
"background": "#1e1e2e",
"foreground": "#afafaf",
"cursor": "#c7c7c7"
}

# Hide initial shell prompt
Hide

# Wait for terminal to be ready
Sleep 1s

# Set a clean, simple prompt
Type "PS1='$ '"
Enter
Sleep 300ms


# Create a clean temporary directory for recording
Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example"
Enter
Sleep 500ms

# Clear the screen to start fresh
Type "clear"
Enter
Sleep 500ms

# Show commands from here
Show

# Now run cz init in the clean environment
Type "cz init"
Sleep 500ms
Enter

# Wait for welcome message and first prompt
Sleep 500ms
Sleep 1s
# Question 1: Please choose a supported config file
# Default is .cz.toml, just press Enter
Enter
Sleep 1s

# Question 2: Please choose a cz (commit rule)
# Default is cz_conventional_commits, just press Enter
Enter
Sleep 1s

# Question 3: Choose the source of the version
# Default is "commitizen: Fetch and set version in commitizen config, just press Enter"
Enter
Sleep 1s

# Question 4: Choose version scheme
# Default is semver, just press Enter
Enter
Sleep 1s

# Question 5: Please enter the correct version format
# Default is "$version", just press Enter
Enter
Sleep 1s

# Question 6: Create changelog automatically on bump
# Default is Yes, just press Enter
Enter
Sleep 1s

# Question 7: Keep major version zero (0.x) during breaking changes
# Default is Yes, just press Enter
Enter
Sleep 1s

# Question 8: What types of pre-commit hook you want to install?
# Default is [commit-msg], just press Enter to accept
Enter
Sleep 1s

# Wait for completion message
Sleep 3s
33 changes: 31 additions & 2 deletions scripts/gen_cli_help_screenshots.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either rename this file or make your change a separate script. I prefer to make it a separate script.

Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,37 @@ def _export_cmd_as_svg(cmd: str, file_path: Path) -> None:
print("Saved to:", file_path.as_posix())


# TODO: generate the screenshot of cz init interactive mode
# TODO: generate the screenshot of cz commit interactive mode
def gen_interactive_screenshots() -> None:
"""Generate GIF screenshots for interactive commands using VHS."""
images_root = Path(__file__).parent.parent / "docs" / "images"

vhs_files = ["init.tape", "commit.tape"]
Copy link
Collaborator

@bearomorphism bearomorphism Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding the tape files, we can just list all *.tape files under the dedicated folder and process them. Also, we don't need to check the existence of vhs_path in the following for loop if we use this approach.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can just write a shell script in docspublish.yml

For example,

vhs docs/images/*.tape

(not sure if the above script works, but you probably know what I mean)


for vhs_file in vhs_files:
vhs_path = images_root / vhs_file
if vhs_path.exists():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_file() should be used if you want to check whether a file exists

print(f"Processing VHS file: {vhs_file}")
try:
subprocess.run(
["vhs", str(vhs_path)],
check=True,
cwd=images_root.as_posix(),
)
gif_file = vhs_file.replace(".tape", ".gif")
print(f"✓ Generated {gif_file} from {vhs_file}")
except subprocess.CalledProcessError as e:
print(f"✗ Error processing {vhs_file}: {e}")
raise
except FileNotFoundError:
print(
"VHS is not installed. Please install it from: "
"https://github.com/charmbracelet/vhs"
)
raise
else:
print(f"Warning: {vhs_file} not found, skipping")


if __name__ == "__main__":
gen_cli_help_screenshots()
gen_interactive_screenshots()