@biggora/claude-plugins 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -1
- package/README.md +13 -13
- package/codex-cli-workspace/iteration-1/benchmark.json +122 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/eval_metadata.json +13 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/grading.json +52 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/outputs/response.md +163 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/grading.json +58 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/outputs/response.md +151 -0
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +13 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +52 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +86 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +58 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +164 -0
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/eval_metadata.json +13 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/grading.json +52 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/outputs/response.md +130 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/grading.json +64 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/outputs/response.md +209 -0
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/timing.json +5 -0
- package/codex-cli-workspace/iteration-1/review.html +1325 -0
- package/gemini-cli-workspace/iteration-1/benchmark.json +86 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/eval_metadata.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/outputs/response.md +401 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/outputs/response.md +405 -0
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +212 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +427 -0
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/eval_metadata.json +32 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/grading.json +32 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/outputs/response.md +171 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/grading.json +32 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/outputs/response.md +199 -0
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-1/review.html +1325 -0
- package/gemini-cli-workspace/iteration-2/benchmark.json +173 -0
- package/gemini-cli-workspace/iteration-2/benchmark.md +28 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/eval_metadata.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/outputs/response.md +195 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/outputs/response.md +377 -0
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/eval_metadata.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/outputs/response.md +127 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/grading.json +37 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/outputs/response.md +164 -0
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/eval_metadata.json +32 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/grading.json +32 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/outputs/response.md +91 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/grading.json +32 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/outputs/response.md +112 -0
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/timing.json +5 -0
- package/gemini-cli-workspace/iteration-2/eval-viewer.html +1325 -0
- package/package.json +1 -1
- package/screen-recording-workspace/evals.json +41 -0
- package/screen-recording-workspace/iteration-1/benchmark.json +102 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/eval_metadata.json +31 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/eval_metadata.json +31 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/eval_metadata.json +31 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/grading.json +11 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/record_screen.py +67 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/timing.json +5 -0
- package/screen-recording-workspace/iteration-1/review.html +1325 -0
- package/src/skills/codex-cli/SKILL.md +21 -11
- package/src/skills/codex-cli/evals/evals.json +47 -0
- package/src/skills/gemini-cli/SKILL.md +27 -13
- package/src/skills/gemini-cli/evals/evals.json +46 -0
- package/src/skills/gemini-cli/references/commands.md +21 -14
- package/src/skills/gemini-cli/references/configuration.md +23 -18
- package/src/skills/gemini-cli/references/headless-and-scripting.md +7 -17
- package/src/skills/gemini-cli/references/mcp-and-extensions.md +12 -6
- package/src/skills/notebook-lm/SKILL.md +1 -1
- package/src/skills/screen-recording/SKILL.md +243 -213
- package/src/skills/screen-recording/references/design-patterns.md +4 -2
- package/src/skills/screen-recording/references/ffmpeg-recording.md +473 -0
- package/src/skills/screen-recording/references/{approach1-programmatic.md → programmatic-generation.md} +45 -22
- package/src/skills/screen-recording/references/python-fallback.md +222 -0
- package/src/skills/tm-search/SKILL.md +242 -106
- package/src/skills/tm-search/evals/evals.json +23 -0
- package/src/skills/tm-search/references/scraping-fallback.md +60 -95
- package/src/skills/tm-search/scripts/tm_search.py +453 -375
- package/src/skills/screen-recording/references/approach2-xvfb.md +0 -232
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
# Approach 2: Virtual Display Recording (Xvfb + FFmpeg x11grab)
|
|
2
|
-
|
|
3
|
-
Capture a real running application on a virtual screen.
|
|
4
|
-
|
|
5
|
-
## How It Works
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
Xvfb :99 ←── virtual display (invisible, in RAM)
|
|
9
|
-
↑
|
|
10
|
-
Your app runs here (DISPLAY=:99)
|
|
11
|
-
↓
|
|
12
|
-
FFmpeg x11grab ←── records the virtual display → MP4
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Full Working Template
|
|
16
|
-
|
|
17
|
-
```python
|
|
18
|
-
#!/usr/bin/env python3
|
|
19
|
-
"""
|
|
20
|
-
Virtual Display Screen Recorder
|
|
21
|
-
Launches a real app on a virtual display and records it.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
import subprocess, os, time, signal, shutil
|
|
25
|
-
|
|
26
|
-
WIDTH, HEIGHT = 1280, 720
|
|
27
|
-
DISPLAY_NUM = ":99"
|
|
28
|
-
FPS = 24
|
|
29
|
-
DURATION = 30 # seconds to record
|
|
30
|
-
OUTPUT = "/home/claude/recording.mp4"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def start_virtual_display():
|
|
34
|
-
"""Start Xvfb virtual display"""
|
|
35
|
-
proc = subprocess.Popen([
|
|
36
|
-
"Xvfb", DISPLAY_NUM,
|
|
37
|
-
"-screen", "0", f"{WIDTH}x{HEIGHT}x24",
|
|
38
|
-
"-ac", "-nolisten", "tcp"
|
|
39
|
-
], stderr=subprocess.DEVNULL)
|
|
40
|
-
time.sleep(1.0) # wait for display to initialize
|
|
41
|
-
print(f"✅ Virtual display {DISPLAY_NUM} started (PID {proc.pid})")
|
|
42
|
-
return proc
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def start_recording(output_path, duration=None):
|
|
46
|
-
"""Start FFmpeg recording of virtual display"""
|
|
47
|
-
cmd = [
|
|
48
|
-
"ffmpeg",
|
|
49
|
-
"-f", "x11grab",
|
|
50
|
-
"-video_size", f"{WIDTH}x{HEIGHT}",
|
|
51
|
-
"-framerate", str(FPS),
|
|
52
|
-
"-i", DISPLAY_NUM,
|
|
53
|
-
"-c:v", "libx264",
|
|
54
|
-
"-preset", "ultrafast",
|
|
55
|
-
"-pix_fmt", "yuv420p",
|
|
56
|
-
]
|
|
57
|
-
if duration:
|
|
58
|
-
cmd.extend(["-t", str(duration)])
|
|
59
|
-
cmd.extend([output_path, "-y", "-loglevel", "quiet"])
|
|
60
|
-
|
|
61
|
-
proc = subprocess.Popen(cmd)
|
|
62
|
-
time.sleep(0.5)
|
|
63
|
-
print(f"✅ Recording started → {output_path}")
|
|
64
|
-
return proc
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def run_app_on_display(app_command, env_extra=None):
|
|
68
|
-
"""Run an application on the virtual display"""
|
|
69
|
-
env = os.environ.copy()
|
|
70
|
-
env["DISPLAY"] = DISPLAY_NUM
|
|
71
|
-
if env_extra:
|
|
72
|
-
env.update(env_extra)
|
|
73
|
-
proc = subprocess.Popen(app_command, env=env, stderr=subprocess.DEVNULL)
|
|
74
|
-
return proc
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def record_session(app_fn, duration=30, output=OUTPUT):
|
|
78
|
-
"""
|
|
79
|
-
Full recording session:
|
|
80
|
-
1. Start virtual display
|
|
81
|
-
2. Start recording
|
|
82
|
-
3. Run app_fn(display) — your automation code
|
|
83
|
-
4. Stop recording, stop display
|
|
84
|
-
"""
|
|
85
|
-
xvfb = start_virtual_display()
|
|
86
|
-
recorder = start_recording(output, duration)
|
|
87
|
-
|
|
88
|
-
try:
|
|
89
|
-
app_fn(DISPLAY_NUM)
|
|
90
|
-
# Wait remaining time or until done
|
|
91
|
-
time.sleep(duration)
|
|
92
|
-
finally:
|
|
93
|
-
recorder.send_signal(signal.SIGINT)
|
|
94
|
-
recorder.wait()
|
|
95
|
-
xvfb.terminate()
|
|
96
|
-
xvfb.wait()
|
|
97
|
-
print(f"✅ Recording saved: {os.path.getsize(output):,} bytes")
|
|
98
|
-
|
|
99
|
-
return output
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# ── EXAMPLE: Record a Python Tkinter app ─────────────────────────────────────
|
|
103
|
-
|
|
104
|
-
def my_tkinter_app_script():
|
|
105
|
-
return '''
|
|
106
|
-
import tkinter as tk
|
|
107
|
-
import time
|
|
108
|
-
|
|
109
|
-
root = tk.Tk()
|
|
110
|
-
root.title("My App Demo")
|
|
111
|
-
root.geometry("1280x720")
|
|
112
|
-
root.configure(bg="#0c0c20")
|
|
113
|
-
|
|
114
|
-
label = tk.Label(root, text="Loading...", font=("Arial", 48),
|
|
115
|
-
bg="#0c0c20", fg="white")
|
|
116
|
-
label.pack(pady=200)
|
|
117
|
-
|
|
118
|
-
def update():
|
|
119
|
-
texts = ["Detecting issues...", "Processing...", "✅ Complete!", "100% Accurate"]
|
|
120
|
-
for i, t in enumerate(texts):
|
|
121
|
-
root.after(i * 2000, lambda t=t: label.configure(text=t))
|
|
122
|
-
root.after(8000, root.destroy)
|
|
123
|
-
|
|
124
|
-
root.after(500, update)
|
|
125
|
-
root.mainloop()
|
|
126
|
-
'''
|
|
127
|
-
|
|
128
|
-
def run_demo(display):
|
|
129
|
-
# Write app to temp file
|
|
130
|
-
with open('/tmp/demo_app.py', 'w') as f:
|
|
131
|
-
f.write(my_tkinter_app_script())
|
|
132
|
-
|
|
133
|
-
env = os.environ.copy()
|
|
134
|
-
env["DISPLAY"] = display
|
|
135
|
-
subprocess.Popen(["python3", "/tmp/demo_app.py"], env=env)
|
|
136
|
-
time.sleep(10) # let app run
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
# ── EXAMPLE: Record a Chromium browser session ───────────────────────────────
|
|
140
|
-
|
|
141
|
-
def record_browser(url, duration=20, output=OUTPUT):
|
|
142
|
-
"""Record a browser navigating to a URL"""
|
|
143
|
-
xvfb = start_virtual_display()
|
|
144
|
-
recorder = start_recording(output, duration)
|
|
145
|
-
|
|
146
|
-
env = os.environ.copy()
|
|
147
|
-
env["DISPLAY"] = DISPLAY_NUM
|
|
148
|
-
|
|
149
|
-
# Launch Chromium in window mode (not headless — we WANT it visible)
|
|
150
|
-
subprocess.Popen([
|
|
151
|
-
"chromium", "--no-sandbox",
|
|
152
|
-
f"--window-size={WIDTH},{HEIGHT}",
|
|
153
|
-
"--window-position=0,0",
|
|
154
|
-
"--start-maximized",
|
|
155
|
-
url
|
|
156
|
-
], env=env, stderr=subprocess.DEVNULL)
|
|
157
|
-
|
|
158
|
-
time.sleep(duration)
|
|
159
|
-
recorder.send_signal(signal.SIGINT)
|
|
160
|
-
recorder.wait()
|
|
161
|
-
xvfb.terminate()
|
|
162
|
-
print(f"✅ Browser recording saved: {output}")
|
|
163
|
-
return output
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# ── POST-PROCESSING ───────────────────────────────────────────────────────────
|
|
167
|
-
|
|
168
|
-
def add_narration(video_path, narration_text, output_path):
|
|
169
|
-
"""Add TTS narration to a recorded video"""
|
|
170
|
-
import pyttsx3
|
|
171
|
-
|
|
172
|
-
engine = pyttsx3.init()
|
|
173
|
-
engine.setProperty('rate', 140)
|
|
174
|
-
engine.save_to_file(narration_text, '/tmp/narration.wav')
|
|
175
|
-
engine.runAndWait()
|
|
176
|
-
|
|
177
|
-
subprocess.run([
|
|
178
|
-
'ffmpeg', '-i', '/tmp/narration.wav',
|
|
179
|
-
'-c:a', 'libmp3lame', '-b:a', '128k',
|
|
180
|
-
'/tmp/narration.mp3', '-y', '-loglevel', 'quiet'
|
|
181
|
-
])
|
|
182
|
-
|
|
183
|
-
subprocess.run([
|
|
184
|
-
'ffmpeg', '-i', video_path, '-i', '/tmp/narration.mp3',
|
|
185
|
-
'-c:v', 'copy', '-c:a', 'aac',
|
|
186
|
-
'-shortest', output_path, '-y', '-loglevel', 'quiet'
|
|
187
|
-
])
|
|
188
|
-
return output_path
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def add_overlay_text(video_path, text, position="bottom", output_path=None):
|
|
192
|
-
"""Add text overlay to recorded video using FFmpeg"""
|
|
193
|
-
if not output_path:
|
|
194
|
-
output_path = video_path.replace('.mp4', '_overlay.mp4')
|
|
195
|
-
|
|
196
|
-
if position == "bottom":
|
|
197
|
-
vf = f"drawtext=text='{text}':fontcolor=white:fontsize=24:x=(w-text_w)/2:y=h-th-20:box=1:boxcolor=black@0.5"
|
|
198
|
-
else:
|
|
199
|
-
vf = f"drawtext=text='{text}':fontcolor=white:fontsize=24:x=20:y=20"
|
|
200
|
-
|
|
201
|
-
subprocess.run([
|
|
202
|
-
'ffmpeg', '-i', video_path, '-vf', vf,
|
|
203
|
-
output_path, '-y', '-loglevel', 'quiet'
|
|
204
|
-
])
|
|
205
|
-
return output_path
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if __name__ == "__main__":
|
|
209
|
-
result = record_session(run_demo, duration=12, output=OUTPUT)
|
|
210
|
-
# Add narration
|
|
211
|
-
final = add_narration(result, "This is our automated UI demo.",
|
|
212
|
-
"/home/claude/final_recording.mp4")
|
|
213
|
-
shutil.copy(final, "/mnt/user-data/outputs/recording.mp4")
|
|
214
|
-
print(f"🎉 Done: /mnt/user-data/outputs/recording.mp4")
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## When to Use This Approach
|
|
218
|
-
|
|
219
|
-
✅ When you need to show a REAL running application
|
|
220
|
-
✅ When demonstrating web UI (real browser rendering)
|
|
221
|
-
✅ When the app has complex visual state hard to reproduce with Pillow
|
|
222
|
-
|
|
223
|
-
❌ Don't use for simple text/graphic demos (too slow — use Approach 1)
|
|
224
|
-
❌ Avoid if network access to the app is needed (may be blocked)
|
|
225
|
-
|
|
226
|
-
## Important Notes
|
|
227
|
-
|
|
228
|
-
- Xvfb uses RAM for the framebuffer — 1280x720x24 ≈ 3.5MB per frame
|
|
229
|
-
- Always kill both `ffmpeg` and `Xvfb` in a `finally` block to avoid orphan processes
|
|
230
|
-
- Use `DISPLAY=:99` not `:0` to avoid conflicts with any host display
|
|
231
|
-
- FFmpeg's `-preset ultrafast` is recommended for real-time capture
|
|
232
|
-
- For longer recordings (>60s), consider `-crf 28` to reduce file size
|