[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DC460C1414N18VAPEZDCDF":3,"skill-same:01M6DC460C1414N18VAPEZDCDF":58},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":33,"linkOnly":34,"markdownContent":35,"markdownBody":36,"frontMatter":37,"refName":38,"commitSha":39,"skillDirectory":40,"forksCount":14,"repositoryHtmlUrl":41,"repositoryHomepageUrl":6,"ownerHtmlUrl":42,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M6DC460C1414N18VAPEZDCDF","video-stabilize",null,"Use when stabilizing a shaky \u002F handheld \u002F camera-shake video so it looks steadied (locked-down or smooth-pan). PRIMARY method = ffmpeg libvidstab TWO-PASS — vidstabdetect (analyze → writes a .trf transforms file) then vidstabtransform (read the .trf → render the steadied clip), with adaptive.","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvideo-stabilize\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32],"Video","video stabilize","file","analyze","read","use","clip","camera","ffmpeg","2026-11-10 10:12:30",false,"---\nname: video-stabilize\ndescription: \"Use when stabilizing a shaky \u002F handheld \u002F camera-shake video so it looks steadied (locked-down or smooth-pan). PRIMARY method = ffmpeg libvidstab TWO-PASS — vidstabdetect (analyze → writes a .trf transforms file) then vidstabtransform (read the .trf → render the steadied clip), with adaptive.\"\n---\n\n# Video stabilization (ffmpeg libvidstab, 2-pass)\n\nSteady a shaky clip. Real implementation lives in\n`media_studio\u002Ffeatures\u002Fstabilize.py` (the 2-pass vidstab engine) with the\nmotion-measurement helper in `media_studio\u002Ffeatures\u002Fmotion.py`. Both go through\nthe shared drained ffmpeg seam `media_studio\u002Fffmpeg.py:run`. **Every ffmpeg argv\nbelow is copied from those modules — nothing here is invented.**\n\n## When to use vs NOT\n\nUSE it when the footage is genuinely shaky: handheld walking, body-cam, drone\nbuffeting, gimbal-less phone video, or any clip whose `motion.py` energy curve is\nhigh *and erratic* (high-frequency jitter, not a smooth pan).\n\nDo NOT use it when:\n- The camera is on a tripod \u002F locked-down — there is nothing to correct and the\n  adaptive crop only throws away pixels.\n- The motion is *intentional*: deliberate whip-pans, dolly moves, fast sports\n  action. vidstab will fight the move and produce an uncanny \"floaty\" result.\n- The shake is **rolling-shutter jello** (skew\u002Fwobble of vertical lines).\n  vidstab models translation + rotation, not per-scanline shear — it will not fix\n  jello and may amplify it. Use a deshake\u002Frolling-shutter tool instead.\n- The frames are motion-blurred from the shake itself. Stabilization re-aligns\n  blurred frames; it cannot un-blur them. Re-shoot.\n- ffmpeg has no libvidstab (see Pitfall 1) — then it is reported as unavailable,\n  the clip is passed through unchanged, never silently \"stabilized\".\n\n## The two passes (this is the whole method)\n\nlibvidstab cannot stabilize in one shot — it must first *analyze* the whole clip\nto learn the camera trajectory, then *transform* against that trajectory:\n\n```\nPASS 1  vidstabdetect    decode → write transforms file (.trf)   [no video out]\nPASS 2  vidstabtransform read .trf → render steadied clip\n```\n\nThe `.trf` is an intermediate written next to the output (`\u003Cout>.trf`) and\ncleaned up afterwards (`stabilize.py: StabilizeEngine._trf_path` \u002F the `finally`\nunlink). Progress is split 0–50 % (detect) \u002F 50–100 % (transform).\n\n### Exact commands\n\nThese are exactly what `build_detect_argv` \u002F `build_transform_argv` emit\n(`stabilize.py` lines ~115–184), with the default tunables.\n\nPASS 1 — analyze (writes `out.trf`, produces no video via `-f null -`):\n\n```bash\nffmpeg -hide_banner -nostdin -y -i IN.mp4 \\\n  -vf \"vidstabdetect=shakiness=5:accuracy=15:result=OUT.trf\" \\\n  -f null -progress pipe:1 -nostats -\n```\n\nPASS 2 — transform (reads `out.trf`, re-encodes h264, copies audio):\n\n```bash\nffmpeg -hide_banner -nostdin -y -i IN.mp4 \\\n  -vf \"vidstabtransform=input=OUT.trf:smoothing=10:optzoom=1\" \\\n  -c:v libx264 -c:a copy -progress pipe:1 -nostats OUT.mp4\n```\n\nNotes baked into the source:\n- `-f null -` on PASS 1: the detect pass only needs the `.trf`; decoding to null\n  makes it fast (no encode).\n- `-c:a copy` on PASS 2: the soundtrack is never touched by the pre-step.\n- `-progress pipe:1 -nostats`: lets `ffmpeg.run` drain stdout (see Pitfall 4).\n- `-nostdin`: stabilize is a pipeline pre-step; never let ffmpeg grab the TTY.\n\n## Tunables (defaults from stabilize.py)\n\nRead from `settings` by `_stab_settings`, each coerced to `int` so a stray wire\nstring can never reach the filter expression unparsed:\n\n| setting key     | filter param | default | meaning |\n|-----------------|--------------|---------|---------|\n| `stabShakiness` | `shakiness`  | 5 (1–10) | how shaky the input is; raise for very jittery footage |\n| `stabAccuracy`  | `accuracy`   | 15 (1–15) | detection accuracy; 15 = max (slowest analyze) |\n| `stabSmoothing` | `smoothing`  | 10 | smoothing window in frames *before+after*; higher = steadier but more \"locked-down\"\u002Ffloaty |\n| `stabOptzoom`   | `optzoom`    | 1 | adaptive zoom mode — 1 crops\u002Fzooms just enough to hide the black borders the warp introduces |\n\n### The crop \u002F zoom vs field-of-view tradeoff\n\nWarping each frame to cancel shake exposes empty (black) edges. `optzoom=1`\nadaptively zooms in so those edges are pushed off-screen — the cost is **lost\nfield of view** and a slight resolution hit (you are upscaling a crop). The\nsteadier you ask for (higher `smoothing`), the more the trajectory deviates from\neach raw frame, the *more* it must zoom, the *more* FOV you lose. So:\n- Mild shake → low smoothing, minimal zoom, FOV mostly preserved.\n- Violent shake → either accept a heavier crop (higher zoom) or accept residual\n  black border judder. There is no free steadiness.\n- `optzoom=0` would leave the borders visible (you'd have to crop in post). The\n  module deliberately defaults to adaptive `optzoom=1`.\n\n## Deciding IF a clip needs stabilization (motion.py)\n\n`motion.py` measures per-window **motion energy** so you can gate stabilization\n(and avoid \"stabilizing\" a tripod shot). Two pure measures, zero model downloads:\n\n- `frame_diff_energy(prev, cur)` — mean `cv2.absdiff` \u002F 255 → `[0,1]` (the floor\n  default, `mode=\"absdiff\"`).\n- `farneback_flow_magnitude(prev_gray, cur_gray)` — mean dense optical-flow\n  magnitude via `cv2.calcOpticalFlowFarneback(prev, cur, None, 0.5, 3, 15, 3, 5,\n  1.2, 0)`, squashed `m\u002F(m+1)` into `[0,1)` (`mode=\"flow\"`, denser \u002F more robust\n  to illumination flicker).\n\n`compute_motion_signals(path, duration, mode=...)` samples one frame per window\nmidpoint, scores adjacent pairs, min-max normalizes, and returns a `SignalTrack`.\nHeuristic: a clip with *sustained high* motion energy that is *erratic* (not a\nsingle smooth ramp) is a stabilize candidate; uniformly low energy = tripod =\nskip. Note the normalized curve is **relative within the clip** — a flat\nhigh-shake clip min-max-normalizes toward 0, so look at the raw `meta[\"raw\"]`\nmagnitudes, not just the normalized `value`, when thresholding shake absolutely.\n\n## Pitfalls that actually bite\n\n1. **libvidstab is a GPL *build* option — it is often missing.**\n   `vidstabdetect`\u002F`vidstabtransform` exist only when ffmpeg was compiled\n   `--enable-libvidstab`. A stripped\u002FLGPL bundle has neither. The module probes\n   with `ffmpeg -hide_banner -filters` (`vidstab_available`) and, if missing,\n   emits the typed notice `stabilize.unavailable` and **passes the clip through\n   unchanged** — the skip is always *reported*, never swallowed\n   (`make_unavailable_notice` \u002F `stabilize_clip`). Fix = rebuild\u002Fbundle ffmpeg\n   with `--enable-libvidstab`. Verify yourself:\n   ```bash\n   ffmpeg -hide_banner -filters | grep vidstab\n   ```\n   Expect both `vidstabdetect` and `vidstabtransform`. The dev-host PATH ffmpeg\n   (winget\u002Fgyan build) has it; a shipped LGPL bundle would not.\n\n2. **Windows `C:\\` paths break vidstab's `:` option separator.**\n   vidstab uses `:` to separate filter options, so a Windows `.trf` path like\n   `C:\\out\\clip.trf` makes ffmpeg read `C` as an option and `\\out\\clip.trf` as a\n   value → garbage. The module forward-slashes the trf path before building the\n   filter string: `str(trf_path).replace(\"\\\\\", \"\u002F\")` (both `build_detect_argv`\n   and `build_transform_argv`). Always pass the `.trf` with forward slashes.\n\n3. **The two passes MUST agree on the .trf and the input.** PASS 2's\n   `input=\u003Ctrf>` must be the file PASS 1 wrote with `result=\u003Ctrf>`, and both must\n   decode the *same* source. If PASS 1 failed\u002Fpartial, the `.trf` is stale or\n   empty and PASS 2 silently under-corrects. The engine treats a non-zero exit\n   from *either* pass as fatal (`StabilizeError`, e.g. \"vidstabdetect failed\n   (ffmpeg exit N)\") rather than rendering against a bad `.trf`.\n\n4. **Never re-implement the ffmpeg drain.** Both passes go through\n   `media_studio\u002Fffmpeg.py:run`, which streams `-progress pipe:1` and drains\n   stdout. This is the \"29-min-freeze lesson\": an undrained ffmpeg pipe fills its\n   OS buffer and the process *hangs* on a long clip. That is why the argv carry\n   `-progress pipe:1 -nostats` and why you must not call ffmpeg with a naive\n   blocking `subprocess` that ignores stdout.\n\n5. **Re-encode + timebase.** PASS 2 re-encodes video to `libx264` (the warp\n   makes copy impossible) but does `-c:a copy`. If the source has variable frame\n   rate or odd timebase, the analyze pass counts frames against the source\n   timeline; a VFR source can drift. For pathological VFR, normalize fps before\n   PASS 1 (`-r`\u002F`fps` filter) so detect and transform share one frame grid.\n\n6. **Don't stabilize twice \u002F don't stabilize what you'll re-crop blindly.**\n   Stabilization is a *pre-step* before reframe (`stabilize_clip` is called\n   BEFORE reframe when `settings['stabilize']` is on). Running it after a reframe\n   crop wastes the FOV budget twice. Order: stabilize → reframe.\n\n7. **GPU note.** libvidstab is **CPU-only** (no CUDA path); the analyze pass is\n   the slow part and scales with `accuracy`. There is **no Hugging Face model**\n   on the default path — vidstab is a native ffmpeg filter and `motion.py`'s\n   floor is pure OpenCV (in the venv, zero downloads). A higher-accuracy flow\n   model (NeuFlow_v2, Apache-2.0, manifest #7) is only an *optional* injectable\n   `MotionBackend` seam in `motion.py` for *measuring* motion — it does not do\n   the stabilizing.\n\n## Worked example\n\nSteady `walk.mp4` (handheld, visibly jittery), default tunables, on Windows.\n\n1. Probe availability (Pitfall 1):\n   ```bash\n   ffmpeg -hide_banner -filters | grep vidstab\n   # vidstabdetect \u002F vidstabtransform both listed → proceed\n   ```\n2. PASS 1 — analyze (note forward-slashed trf path, Pitfall 2):\n   ```bash\n   ffmpeg -hide_banner -nostdin -y -i \"C:\u002Fclips\u002Fwalk.mp4\" \\\n     -vf \"vidstabdetect=shakiness=5:accuracy=15:result=C:\u002Fclips\u002Fwalk.stabilized.trf\" \\\n     -f null -progress pipe:1 -nostats -\n   ```\n3. PASS 2 — transform (reads the same trf, h264 + audio copy):\n   ```bash\n   ffmpeg -hide_banner -nostdin -y -i \"C:\u002Fclips\u002Fwalk.mp4\" \\\n     -vf \"vidstabtransform=input=C:\u002Fclips\u002Fwalk.stabilized.trf:smoothing=10:optzoom=1\" \\\n     -c:v libx264 -c:a copy -progress pipe:1 -nostats \"C:\u002Fclips\u002Fwalk.stabilized.mp4\"\n   ```\n4. Delete `walk.stabilized.trf` (the engine does this in a `finally`).\n5. Inspect: edges should not show black\u002Fjudder (optzoom hid them); the subject\n   should feel locked. If it feels too \"floaty\"\u002Flocked-down, lower `smoothing`\n   (e.g. 5); if residual jitter remains, raise `shakiness` (e.g. 8).\n\nIn-process the whole thing is one call —\n`StabilizeEngine(settings).stabilize(in_path, out_path)` — or, as the\npipeline pre-step, `stabilize_clip(in_path, out_path, settings=..., on_notice=...)`\nwhich returns the *original* path (plus a typed notice) when libvidstab is\nabsent. The RPC `stabilize.run({videoId|path})` returns\n`{path, stabilized: bool[, notice]}`.\n","# Video stabilization (ffmpeg libvidstab, 2-pass)\n\nSteady a shaky clip. Real implementation lives in\n`media_studio\u002Ffeatures\u002Fstabilize.py` (the 2-pass vidstab engine) with the\nmotion-measurement helper in `media_studio\u002Ffeatures\u002Fmotion.py`. Both go through\nthe shared drained ffmpeg seam `media_studio\u002Fffmpeg.py:run`. **Every ffmpeg argv\nbelow is copied from those modules — nothing here is invented.**\n\n## When to use vs NOT\n\nUSE it when the footage is genuinely shaky: handheld walking, body-cam, drone\nbuffeting, gimbal-less phone video, or any clip whose `motion.py` energy curve is\nhigh *and erratic* (high-frequency jitter, not a smooth pan).\n\nDo NOT use it when:\n- The camera is on a tripod \u002F locked-down — there is nothing to correct and the\n  adaptive crop only throws away pixels.\n- The motion is *intentional*: deliberate whip-pans, dolly moves, fast sports\n  action. vidstab will fight the move and produce an uncanny \"floaty\" result.\n- The shake is **rolling-shutter jello** (skew\u002Fwobble of vertical lines).\n  vidstab models translation + rotation, not per-scanline shear — it will not fix\n  jello and may amplify it. Use a deshake\u002Frolling-shutter tool instead.\n- The frames are motion-blurred from the shake itself. Stabilization re-aligns\n  blurred frames; it cannot un-blur them. Re-shoot.\n- ffmpeg has no libvidstab (see Pitfall 1) — then it is reported as unavailable,\n  the clip is passed through unchanged, never silently \"stabilized\".\n\n## The two passes (this is the whole method)\n\nlibvidstab cannot stabilize in one shot — it must first *analyze* the whole clip\nto learn the camera trajectory, then *transform* against that trajectory:\n\n```\nPASS 1  vidstabdetect    decode → write transforms file (.trf)   [no video out]\nPASS 2  vidstabtransform read .trf → render steadied clip\n```\n\nThe `.trf` is an intermediate written next to the output (`\u003Cout>.trf`) and\ncleaned up afterwards (`stabilize.py: StabilizeEngine._trf_path` \u002F the `finally`\nunlink). Progress is split 0–50 % (detect) \u002F 50–100 % (transform).\n\n### Exact commands\n\nThese are exactly what `build_detect_argv` \u002F `build_transform_argv` emit\n(`stabilize.py` lines ~115–184), with the default tunables.\n\nPASS 1 — analyze (writes `out.trf`, produces no video via `-f null -`):\n\n```bash\nffmpeg -hide_banner -nostdin -y -i IN.mp4 \\\n  -vf \"vidstabdetect=shakiness=5:accuracy=15:result=OUT.trf\" \\\n  -f null -progress pipe:1 -nostats -\n```\n\nPASS 2 — transform (reads `out.trf`, re-encodes h264, copies audio):\n\n```bash\nffmpeg -hide_banner -nostdin -y -i IN.mp4 \\\n  -vf \"vidstabtransform=input=OUT.trf:smoothing=10:optzoom=1\" \\\n  -c:v libx264 -c:a copy -progress pipe:1 -nostats OUT.mp4\n```\n\nNotes baked into the source:\n- `-f null -` on PASS 1: the detect pass only needs the `.trf`; decoding to null\n  makes it fast (no encode).\n- `-c:a copy` on PASS 2: the soundtrack is never touched by the pre-step.\n- `-progress pipe:1 -nostats`: lets `ffmpeg.run` drain stdout (see Pitfall 4).\n- `-nostdin`: stabilize is a pipeline pre-step; never let ffmpeg grab the TTY.\n\n## Tunables (defaults from stabilize.py)\n\nRead from `settings` by `_stab_settings`, each coerced to `int` so a stray wire\nstring can never reach the filter expression unparsed:\n\n| setting key     | filter param | default | meaning |\n|-----------------|--------------|---------|---------|\n| `stabShakiness` | `shakiness`  | 5 (1–10) | how shaky the input is; raise for very jittery footage |\n| `stabAccuracy`  | `accuracy`   | 15 (1–15) | detection accuracy; 15 = max (slowest analyze) |\n| `stabSmoothing` | `smoothing`  | 10 | smoothing window in frames *before+after*; higher = steadier but more \"locked-down\"\u002Ffloaty |\n| `stabOptzoom`   | `optzoom`    | 1 | adaptive zoom mode — 1 crops\u002Fzooms just enough to hide the black borders the warp introduces |\n\n### The crop \u002F zoom vs field-of-view tradeoff\n\nWarping each frame to cancel shake exposes empty (black) edges. `optzoom=1`\nadaptively zooms in so those edges are pushed off-screen — the cost is **lost\nfield of view** and a slight resolution hit (you are upscaling a crop). The\nsteadier you ask for (higher `smoothing`), the more the trajectory deviates from\neach raw frame, the *more* it must zoom, the *more* FOV you lose. So:\n- Mild shake → low smoothing, minimal zoom, FOV mostly preserved.\n- Violent shake → either accept a heavier crop (higher zoom) or accept residual\n  black border judder. There is no free steadiness.\n- `optzoom=0` would leave the borders visible (you'd have to crop in post). The\n  module deliberately defaults to adaptive `optzoom=1`.\n\n## Deciding IF a clip needs stabilization (motion.py)\n\n`motion.py` measures per-window **motion energy** so you can gate stabilization\n(and avoid \"stabilizing\" a tripod shot). Two pure measures, zero model downloads:\n\n- `frame_diff_energy(prev, cur)` — mean `cv2.absdiff` \u002F 255 → `[0,1]` (the floor\n  default, `mode=\"absdiff\"`).\n- `farneback_flow_magnitude(prev_gray, cur_gray)` — mean dense optical-flow\n  magnitude via `cv2.calcOpticalFlowFarneback(prev, cur, None, 0.5, 3, 15, 3, 5,\n  1.2, 0)`, squashed `m\u002F(m+1)` into `[0,1)` (`mode=\"flow\"`, denser \u002F more robust\n  to illumination flicker).\n\n`compute_motion_signals(path, duration, mode=...)` samples one frame per window\nmidpoint, scores adjacent pairs, min-max normalizes, and returns a `SignalTrack`.\nHeuristic: a clip with *sustained high* motion energy that is *erratic* (not a\nsingle smooth ramp) is a stabilize candidate; uniformly low energy = tripod =\nskip. Note the normalized curve is **relative within the clip** — a flat\nhigh-shake clip min-max-normalizes toward 0, so look at the raw `meta[\"raw\"]`\nmagnitudes, not just the normalized `value`, when thresholding shake absolutely.\n\n## Pitfalls that actually bite\n\n1. **libvidstab is a GPL *build* option — it is often missing.**\n   `vidstabdetect`\u002F`vidstabtransform` exist only when ffmpeg was compiled\n   `--enable-libvidstab`. A stripped\u002FLGPL bundle has neither. The module probes\n   with `ffmpeg -hide_banner -filters` (`vidstab_available`) and, if missing,\n   emits the typed notice `stabilize.unavailable` and **passes the clip through\n   unchanged** — the skip is always *reported*, never swallowed\n   (`make_unavailable_notice` \u002F `stabilize_clip`). Fix = rebuild\u002Fbundle ffmpeg\n   with `--enable-libvidstab`. Verify yourself:\n   ```bash\n   ffmpeg -hide_banner -filters | grep vidstab\n   ```\n   Expect both `vidstabdetect` and `vidstabtransform`. The dev-host PATH ffmpeg\n   (winget\u002Fgyan build) has it; a shipped LGPL bundle would not.\n\n2. **Windows `C:\\` paths break vidstab's `:` option separator.**\n   vidstab uses `:` to separate filter options, so a Windows `.trf` path like\n   `C:\\out\\clip.trf` makes ffmpeg read `C` as an option and `\\out\\clip.trf` as a\n   value → garbage. The module forward-slashes the trf path before building the\n   filter string: `str(trf_path).replace(\"\\\\\", \"\u002F\")` (both `build_detect_argv`\n   and `build_transform_argv`). Always pass the `.trf` with forward slashes.\n\n3. **The two passes MUST agree on the .trf and the input.** PASS 2's\n   `input=\u003Ctrf>` must be the file PASS 1 wrote with `result=\u003Ctrf>`, and both must\n   decode the *same* source. If PASS 1 failed\u002Fpartial, the `.trf` is stale or\n   empty and PASS 2 silently under-corrects. The engine treats a non-zero exit\n   from *either* pass as fatal (`StabilizeError`, e.g. \"vidstabdetect failed\n   (ffmpeg exit N)\") rather than rendering against a bad `.trf`.\n\n4. **Never re-implement the ffmpeg drain.** Both passes go through\n   `media_studio\u002Fffmpeg.py:run`, which streams `-progress pipe:1` and drains\n   stdout. This is the \"29-min-freeze lesson\": an undrained ffmpeg pipe fills its\n   OS buffer and the process *hangs* on a long clip. That is why the argv carry\n   `-progress pipe:1 -nostats` and why you must not call ffmpeg with a naive\n   blocking `subprocess` that ignores stdout.\n\n5. **Re-encode + timebase.** PASS 2 re-encodes video to `libx264` (the warp\n   makes copy impossible) but does `-c:a copy`. If the source has variable frame\n   rate or odd timebase, the analyze pass counts frames against the source\n   timeline; a VFR source can drift. For pathological VFR, normalize fps before\n   PASS 1 (`-r`\u002F`fps` filter) so detect and transform share one frame grid.\n\n6. **Don't stabilize twice \u002F don't stabilize what you'll re-crop blindly.**\n   Stabilization is a *pre-step* before reframe (`stabilize_clip` is called\n   BEFORE reframe when `settings['stabilize']` is on). Running it after a reframe\n   crop wastes the FOV budget twice. Order: stabilize → reframe.\n\n7. **GPU note.** libvidstab is **CPU-only** (no CUDA path); the analyze pass is\n   the slow part and scales with `accuracy`. There is **no Hugging Face model**\n   on the default path — vidstab is a native ffmpeg filter and `motion.py`'s\n   floor is pure OpenCV (in the venv, zero downloads). A higher-accuracy flow\n   model (NeuFlow_v2, Apache-2.0, manifest #7) is only an *optional* injectable\n   `MotionBackend` seam in `motion.py` for *measuring* motion — it does not do\n   the stabilizing.\n\n## Worked example\n\nSteady `walk.mp4` (handheld, visibly jittery), default tunables, on Windows.\n\n1. Probe availability (Pitfall 1):\n   ```bash\n   ffmpeg -hide_banner -filters | grep vidstab\n   # vidstabdetect \u002F vidstabtransform both listed → proceed\n   ```\n2. PASS 1 — analyze (note forward-slashed trf path, Pitfall 2):\n   ```bash\n   ffmpeg -hide_banner -nostdin -y -i \"C:\u002Fclips\u002Fwalk.mp4\" \\\n     -vf \"vidstabdetect=shakiness=5:accuracy=15:result=C:\u002Fclips\u002Fwalk.stabilized.trf\" \\\n     -f null -progress pipe:1 -nostats -\n   ```\n3. PASS 2 — transform (reads the same trf, h264 + audio copy):\n   ```bash\n   ffmpeg -hide_banner -nostdin -y -i \"C:\u002Fclips\u002Fwalk.mp4\" \\\n     -vf \"vidstabtransform=input=C:\u002Fclips\u002Fwalk.stabilized.trf:smoothing=10:optzoom=1\" \\\n     -c:v libx264 -c:a copy -progress pipe:1 -nostats \"C:\u002Fclips\u002Fwalk.stabilized.mp4\"\n   ```\n4. Delete `walk.stabilized.trf` (the engine does this in a `finally`).\n5. Inspect: edges should not show black\u002Fjudder (optzoom hid them); the subject\n   should feel locked. If it feels too \"floaty\"\u002Flocked-down, lower `smoothing`\n   (e.g. 5); if residual jitter remains, raise `shakiness` (e.g. 8).\n\nIn-process the whole thing is one call —\n`StabilizeEngine(settings).stabilize(in_path, out_path)` — or, as the\npipeline pre-step, `stabilize_clip(in_path, out_path, settings=..., on_notice=...)`\nwhich returns the *original* path (plus a typed notice) when libvidstab is\nabsent. The RPC `stabilize.run({videoId|path})` returns\n`{path, stabilized: bool[, notice]}`.\n",{"name":5,"description":7},"main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Fskills\u002Fvideo-stabilize","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill video-stabilize",{"tool":50,"command":51},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill video-stabilize",{"tool":53,"command":54},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill video-stabilize","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvideo-stabilize\u002FSKILL.md",true,[],[59,79,107,134,148,164],{"skillNo":60,"name":61,"nameZh":6,"description":62,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":63,"categories":64,"keywords":65,"publishedAt":33},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[66,67,68,69,70,71,72,73,74,29,75,76,77,78,26],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","context","repo","injection","execution",{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":88,"publishedAt":33},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[89,90,91,92,93,27,94,95,96,97,98,99,100,101,29,102,103,104,105,106],"openmm md","how","decision","pick","linux","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":108,"name":109,"nameZh":6,"description":110,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":119,"publishedAt":33},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[113,116],{"categoryNo":114,"categoryName":115,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[120,121,122,123,124,125,126,127,128,129,90,130,131,132,133],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":135,"name":136,"nameZh":6,"description":137,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":140,"publishedAt":33},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[136,141,142,143,144,145,146,147],"setup","report","project","installation","project setup","issues","state",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":155,"publishedAt":33},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[154],{"categoryNo":86,"categoryName":87,"taxonomyType":21,"taxonomyTypeDesc":22},[150,156,71,157,158,159,29,160,161,162,163],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":165,"name":141,"nameZh":6,"description":166,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":167,"categories":168,"keywords":169,"publishedAt":33},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[141,143,104,170,145,171],"files","interactive"]