Skip to content

Record hero GIF demo with OBS #7

@poodle64

Description

@poodle64

Summary

Record a compelling hero GIF for the README that shows off Thoth's voice-to-text workflow. The current hero GIF doesn't show the recording indicator (macOS screen recording skips alwaysOnTop transparent windows). OBS captures all window layers and will show the floating mic icon.

Research

  • Ideal length: 10–15 seconds for a hero GIF
  • Target file size: Under 5 MB (GitHub renders large GIFs as static first-frame)
  • Best practice: One focused hero GIF at the top showing the "aha moment", optionally supplemented by feature-specific GIFs further down

Recording Script

Hero GIF — "Press a key. Speak. Text appears."

Setup before recording

  • Open Sublime Text (or any editor) with a file called Meeting notes — Thursday 25 March
  • Pre-type lines 1–5:
    Meeting notes — Thursday 25 March
    
    Attendees: Sarah, Steven
    
    Action items:
    
  • Cursor on line 7, empty
  • Thoth running, hotkey set to F13
  • OBS source: Use macOS Screen Capture (not Window Capture) — this captures all window layers including alwaysOnTop overlays like the recording indicator. Crop to the editor window in post.
  • OBS output: native window resolution, 30 fps, Apple VT H264 Hardware Encoder, CRF 18–22, MP4 format

The take (aim for ~15 seconds total)

Time Action What viewer sees
0–2s Pause. Let the viewer read the existing notes. Static editor with meeting notes
2–3s Press F13. Recording indicator (floating mic icon) appears near cursor
3–12s Speak clearly: "Review the onboarding flow and simplify the permission steps before the next release." Mic icon visible near cursor
12–13s Release F13 (or let VAD stop). Indicator disappears
13–15s Text appears on line 7. Pause to let viewer read. Transcribed sentence visible

Key points

  • The recording indicator floating near the cursor is the visual proof this is system-wide
  • Keep the window clean — no other apps visible
  • Speak at a natural pace, not rushed
  • Do multiple takes — pick the cleanest one

Optional: Feature GIF — "Speak like a pirate"

For the Features section of the README. Shows AI enhancement.

Setup

  • Open Thoth settings, navigate to Enhancement section
  • Have the "Speak like a pirate" prompt visible
  • Switch to a text editor

The take

  • Dictate something normal like "Please send the report to the team by Friday"
  • Text appears as pirate speech (e.g. "Ahoy! Be sendin' that report to the crew by Friday, ye scallywag!")

This is fun and immediately shows the AI enhancement value.


Post-production: Converting to GIF

Step 1: Trim and crop

Watch the OBS recording and note:

  • TRIM_START: seconds to skip from the beginning
  • TRIM_END: seconds to trim from the end
  • Crop coordinates if needed (use ffprobe or ffmpeg cropdetect)

Step 2: Generate text overlays (only if the recording indicator STILL doesn't appear)

If OBS captures the mic icon, skip this step — no overlays needed.

If the icon is still missing, generate plain-text caption PNGs with Pillow:

/Users/paul/miniconda3/envs/automator/bin/python3 << 'PYEOF'
from PIL import Image, ImageDraw, ImageFont

font_path = "/System/Library/Fonts/SFCompact.ttf"
font = ImageFont.truetype(font_path, 48)

labels = {
    "hotkey_pressed": "Hotkey pressed",
    "recording": "Recording…",
    "transcribed": "Transcribed ✓",
}

for name, text in labels.items():
    tmp = Image.new("RGBA", (1, 1), (0, 0, 0, 0))
    d = ImageDraw.Draw(tmp)
    bbox = d.textbbox((0, 0), text, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    pad = 6
    w, h = tw + pad * 2 + 4, th + pad * 2 + 4
    img = Image.new("RGBA", (w, h), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.text((pad + 2 - bbox[0], pad + 2 - bbox[1]), text, fill=(0, 0, 0, 180), font=font)
    d.text((pad - bbox[0], pad - bbox[1]), text, fill=(220, 220, 220, 255), font=font)
    img.save(f"/tmp/{name}.png")
    print(f"/tmp/{name}.png: {img.size}")
PYEOF

Step 3: Convert to GIF

Use the existing script (or manually):

# Without overlays:
FPS=10 TRIM_START=<N> TRIM_END=<N> WIDTH=800 \
  ./scripts/mov-to-hero-gif.sh recording.mp4 docs/screenshots/hero.gif

# With overlays (two-pass ffmpeg):
INPUT="recording.mp4"
OUTPUT="docs/screenshots/hero.gif"
PALETTE=$(mktemp /tmp/palette-XXXXXX.png)

# Pass 1: palette
ffmpeg -y -ss <START> -to <END> -i "$INPUT" \
  -i /tmp/hotkey_pressed.png -i /tmp/recording.png -i /tmp/transcribed.png \
  -filter_complex "
    [0:v]crop=W:H:X:Y,fps=10[base];
    [base][1:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T1_START>,<T1_END>)'[v1];
    [v1][2:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T2_START>,<T2_END>)'[v2];
    [v2][3:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T3_START>,<T3_END>)'[v3];
    [v3]scale=800:-1:flags=lanczos,palettegen=stats_mode=diff[pal]
  " -map "[pal]" "$PALETTE"

# Pass 2: render
ffmpeg -y -ss <START> -to <END> -i "$INPUT" \
  -i /tmp/hotkey_pressed.png -i /tmp/recording.png -i /tmp/transcribed.png \
  -i "$PALETTE" \
  -filter_complex "
    [0:v]crop=W:H:X:Y,fps=10[base];
    [base][1:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T1_START>,<T1_END>)'[v1];
    [v1][2:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T2_START>,<T2_END>)'[v2];
    [v2][3:v]overlay=x=(W-w)/2:y=H-h-30:enable='between(t,<T3_START>,<T3_END>)'[v3];
    [v3]scale=800:-1:flags=lanczos[scaled];
    [scaled][4:v]paletteuse=dither=bayer:bayer_scale=5[out]
  " -map "[out]" "$OUTPUT"

Replace <START>, <END>, crop=W:H:X:Y, and overlay timing placeholders with actual values from the recording.

Step 4: Verify

  • Check file size: target under 5 MB (ideally under 500 KB)
  • Check frame count and duration
  • Extract key frames to verify overlays and crop look correct
  • Update README.md reference if filename changes

Acceptance criteria

  • Hero GIF recorded with OBS showing the floating recording indicator
  • GIF converted and optimised (under 5 MB, 800px wide, 10 fps)
  • README.md updated with the new GIF
  • Optional: pirate mode feature GIF for Features section

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions