diff --git a/.github/workflows/mantis-discord-status-reactions.yml b/.github/workflows/mantis-discord-status-reactions.yml index 45a317ac8db..89e49540a0a 100644 --- a/.github/workflows/mantis-discord-status-reactions.yml +++ b/.github/workflows/mantis-discord-status-reactions.yml @@ -407,6 +407,29 @@ jobs: capture_desktop_lane baseline capture_desktop_lane candidate + make_desktop_preview() { + local lane="$1" + local input="$root/$lane/discord-status-reactions-tool-only-desktop.mp4" + local output="$root/$lane/discord-status-reactions-tool-only-desktop-preview.gif" + local palette="$root/$lane/discord-status-reactions-tool-only-desktop-preview-palette.png" + ffmpeg -y -i "$input" -vf "fps=4,scale=640:-1:flags=lanczos,palettegen=stats_mode=diff" -frames:v 1 -update 1 "$palette" + ffmpeg -y -i "$input" -i "$palette" -lavfi "fps=4,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=3:diff_mode=rectangle" -loop 0 "$output" + rm -f "$palette" + } + + if ! command -v ffmpeg >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ffmpeg || true + fi + if command -v ffmpeg >/dev/null 2>&1; then + if ! make_desktop_preview baseline || ! make_desktop_preview candidate; then + rm -f "$root/baseline/discord-status-reactions-tool-only-desktop-preview.gif" + rm -f "$root/candidate/discord-status-reactions-tool-only-desktop-preview.gif" + echo "::warning::Could not generate animated desktop previews; continuing with screenshots and MP4 links." + fi + else + echo "::warning::ffmpeg is unavailable; skipping animated desktop previews." + fi + baseline_status="$(jq -r '.scenarios[0].status' "$root/baseline/discord-qa-summary.json")" candidate_status="$(jq -r '.scenarios[0].status' "$root/candidate/discord-qa-summary.json")" @@ -432,6 +455,12 @@ jobs: echo "- Candidate screenshot: \`candidate/discord-status-reactions-tool-only-timeline.png\`" echo "- Baseline desktop screenshot: \`baseline/discord-status-reactions-tool-only-desktop.png\`" echo "- Candidate desktop screenshot: \`candidate/discord-status-reactions-tool-only-desktop.png\`" + if [[ -f "$root/baseline/discord-status-reactions-tool-only-desktop-preview.gif" ]]; then + echo "- Baseline desktop preview: \`baseline/discord-status-reactions-tool-only-desktop-preview.gif\`" + fi + if [[ -f "$root/candidate/discord-status-reactions-tool-only-desktop-preview.gif" ]]; then + echo "- Candidate desktop preview: \`candidate/discord-status-reactions-tool-only-desktop-preview.gif\`" + fi echo "- Baseline desktop video: \`baseline/discord-status-reactions-tool-only-desktop.mp4\`" echo "- Candidate desktop video: \`candidate/discord-status-reactions-tool-only-desktop.mp4\`" } > "$root/mantis-report.md" @@ -524,6 +553,12 @@ jobs: cp "$root/candidate/discord-status-reactions-tool-only-timeline.png" "$artifacts_worktree/$artifact_root/candidate.png" cp "$root/baseline/discord-status-reactions-tool-only-desktop.png" "$artifacts_worktree/$artifact_root/baseline-desktop.png" cp "$root/candidate/discord-status-reactions-tool-only-desktop.png" "$artifacts_worktree/$artifact_root/candidate-desktop.png" + has_desktop_previews="false" + if [[ -f "$root/baseline/discord-status-reactions-tool-only-desktop-preview.gif" && -f "$root/candidate/discord-status-reactions-tool-only-desktop-preview.gif" ]]; then + cp "$root/baseline/discord-status-reactions-tool-only-desktop-preview.gif" "$artifacts_worktree/$artifact_root/baseline-desktop-preview.gif" + cp "$root/candidate/discord-status-reactions-tool-only-desktop-preview.gif" "$artifacts_worktree/$artifact_root/candidate-desktop-preview.gif" + has_desktop_previews="true" + fi cp "$root/baseline/discord-status-reactions-tool-only-desktop.mp4" "$artifacts_worktree/$artifact_root/baseline-desktop.mp4" cp "$root/candidate/discord-status-reactions-tool-only-desktop.mp4" "$artifacts_worktree/$artifact_root/candidate-desktop.mp4" cp "$root/comparison.json" "$artifacts_worktree/$artifact_root/comparison.json" @@ -542,6 +577,16 @@ jobs: baseline_status="$(jq -r '.baseline.status' "$root/comparison.json")" candidate_status="$(jq -r '.candidate.status' "$root/comparison.json")" pass="$(jq -r '.pass' "$root/comparison.json")" + preview_section="" + if [[ "$has_desktop_previews" == "true" ]]; then + preview_section="$(cat < | Animated candidate desktop preview | + EOF + )" + fi comment_file="$(mktemp)" cat > "$comment_file" < @@ -564,8 +609,9 @@ jobs: | Baseline desktop/VNC browser | Candidate desktop/VNC browser | | --- | --- | | Baseline Mantis desktop browser screenshot | Candidate Mantis desktop browser screenshot | + ${preview_section} - Videos: + Full videos: - [Baseline desktop MP4](${raw_base}/baseline-desktop.mp4) - [Candidate desktop MP4](${raw_base}/candidate-desktop.mp4) diff --git a/docs/concepts/mantis.md b/docs/concepts/mantis.md index c8ea6d090fa..8c06129ae31 100644 --- a/docs/concepts/mantis.md +++ b/docs/concepts/mantis.md @@ -168,9 +168,10 @@ worktrees, runs `discord-status-reactions-tool-only` against each worktree, and uploads `baseline/`, `candidate/`, `comparison.json`, and `mantis-report.md` as Actions artifacts. It also renders each lane's timeline HTML in a Crabbox desktop browser and publishes those VNC screenshots beside the deterministic -timeline PNGs in the PR comment. The same PR comment links to the desktop MP4 -recordings captured during the VNC browser render, while the screenshots stay -inline for quick review. The workflow builds the Crabbox CLI from +timeline PNGs in the PR comment. The same PR comment embeds lightweight animated +GIF previews generated from the VNC desktop recordings and links to the full +desktop MP4 files, while the screenshots stay inline for quick review. The +workflow builds the Crabbox CLI from `openclaw/crabbox` main so it can use the current desktop/browser lease flags before the next Crabbox binary release is cut.