[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6MAMDAX5S6HYEB9FRWZ2V8H":3,"skill-same:01M6MAMDAX5S6HYEB9FRWZ2V8H":109},{"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":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":64,"repositoryHtmlUrl":65,"repositoryHomepageUrl":66,"ownerHtmlUrl":67,"ownerBlogUrl":68,"ownerDescription":69,"updatedAt":70,"install":71,"resources":84},"01M6MAMDAX5S6HYEB9FRWZ2V8H","openpiv",null,"Particle Image Velocimetry (PIV) analysis with OpenPIV. Use when extracting velocity fields from PIV image pairs, analyzing fluid dynamics or flow visualization experiments, cross-correlating interrogation windows, validating and replacing spurious PIV vectors, or computing vorticity, strain rate, and turbulence statistics from measured velocity fields.","hashgraph-online\u002Fawesome-codex-plugins","hashgraph-online","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F160371962?v=4","01M6CNB6NRJVNNGN14TR01Q6D3","HOL (Hashgraph Online)","01M6JT1HSKKG9V68KQAQGBA7XP",1559,"BSD-3-Clause","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",[5,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"uv","when","piv","extracting","turbulence","fluid dynamics","statistics","physics","velocity","scipy","image","install","edit","write","read","access","Bash","team","analysis","visualization","2026-11-10 10:12:30",false,"---\nname: openpiv\ndescription: Particle Image Velocimetry (PIV) analysis with OpenPIV. Use when extracting velocity fields from PIV image pairs, analyzing fluid dynamics or flow visualization experiments, cross-correlating interrogation windows, validating and replacing spurious PIV vectors, or computing vorticity, strain rate, and turbulence statistics from measured velocity fields.\nlicense: BSD-3-Clause\ncompatibility: Requires Python 3.10+ with openpiv installed (uv pip install openpiv). numpy, scipy, scikit-image, and matplotlib arrive as dependencies. No network access needed after install.\nallowed-tools: Read Write Edit Bash\nmetadata:\n  version: '1.1'\n  category: physical-sciences\n  maintainer: Kalaris Labs\n  tested-against: openpiv 0.25.4\n  contributor: OpenPIV Team\n  tags: particle image velocimetry, PIV, fluid dynamics, flow visualization, physics\n---\n\n# OpenPIV\n\n## Overview\n\nOpenPIV (Open Particle Image Velocimetry) analyzes fluid flow from PIV image pairs. It covers\npreprocessing, cross-correlation, vector validation, outlier replacement, smoothing, and scaling to\nphysical units.\n\nEverything below is verified against **openpiv 0.25.4**. The API moves between releases — check\n`inspect.signature()` before trusting a snippet against a different version.\n\n## When to use\n\nUse this skill when working with experimental PIV or flow-visualization image pairs: measuring 2D\nvelocity fields, tuning interrogation-window parameters, validating vectors, or deriving vorticity,\nstrain rate, and turbulence statistics. For *simulating* flow rather than measuring it, use a CFD\nskill instead.\n\n## Quick Start\n\nInstall OpenPIV:\n\n```bash\nuv pip install openpiv\n\n# Pin it when the analysis needs to be reproducible -- this is the version every\n# snippet below was checked against.\nuv pip install \"openpiv==0.25.4\"\n```\n\nRun PIV analysis on an image pair:\n\n```python\nimport numpy as np\nfrom openpiv import tools, pyprocess, validation, filters, scaling\n\nframe_a = tools.imread(\"image_a.bmp\")\nframe_b = tools.imread(\"image_b.bmp\")\n\n# Cross-correlate. Returns (u, v, s2n) whenever sig2noise_method is not None.\nu, v, s2n = pyprocess.extended_search_area_piv(\n    frame_a.astype(np.int32),\n    frame_b.astype(np.int32),\n    window_size=32,\n    overlap=12,\n    dt=0.02,\n    search_area_size=38,\n    correlation_method=\"linear\",   # required for search_area_size > window_size\n    sig2noise_method=\"peak2peak\",\n)\n\nx, y = pyprocess.get_coordinates(\n    image_size=frame_a.shape,\n    search_area_size=38,\n    overlap=12,\n)\n\n# flags is a boolean array: True marks a spurious vector.\nflags = validation.sig2noise_val(s2n, threshold=1.05)\nu, v = filters.replace_outliers(u, v, flags, method=\"localmean\", max_iter=3, kernel_size=2)\n\n# Scale to physical units, then flip to image coordinates for plotting.\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nx, y, u, v = tools.transform_coordinates(x, y, u, v)\n\ntools.save(\"vectors.txt\", x, y, u, v, flags)\n```\n\nOr use the bundled CLI, which wraps exactly that pipeline:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp --image frame_b.bmp --output_dir results --verbose\n```\n\n## Core Concepts\n\n### PIV Fundamentals\n\nParticle Image Velocimetry is an optical method for measuring fluid velocity by tracking illuminated\ntracer particles between two images.\n\n**Process flow:**\n\n1. Capture an image pair (`frame_a`, `frame_b`) separated by a known time `dt`.\n2. Divide the images into interrogation windows.\n3. Cross-correlate matching windows to find peak displacement.\n4. Validate vectors (signal-to-noise, global range, local median).\n5. Replace spurious vectors with interpolated values.\n6. Scale pixel displacements to physical units.\n\n### Interrogation Window Parameters\n\n**`window_size`** — correlation window in pixels (typically 16–128). Larger windows give better\ncorrelation but coarser spatial resolution.\n\n**`overlap`** — pixels shared between adjacent windows (typically 50–75% of `window_size`). Higher\noverlap raises vector density and cost, but adjacent vectors become correlated rather than\nindependent.\n\n**`search_area_size`** — the window searched in the second frame. Must be ≥ `window_size`; a few\npixels larger accommodates larger displacements. Pair an extended search area with\n`correlation_method=\"linear\"` — the default `\"circular\"` relies on FFT wrap-around and aliases large\ndisplacements into small ones. See `references\u002Fadvanced_algorithms.md`.\n\nRules of thumb: keep the largest displacement under about a quarter of `window_size`, and aim for\n5–10 particles per window.\n\n### Signal-to-Noise Ratio\n\n`s2n` measures how distinct the correlation peak is. `sig2noise_method` controls how it is computed —\n`\"peak2mean\"` (the function default) or `\"peak2peak\"`. **The two are on different scales**, so a\nthreshold tuned for one is meaningless for the other. Typical `peak2peak` thresholds are 1.05–1.3.\n\n```python\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n# flags is bool: True == spurious. `~flags` selects the good vectors.\n```\n\n## Common Operations\n\n### Dynamic Masking\n\nMasking lives in `openpiv.preprocess`, **not** in an `openpiv.masking` module. It returns an\n`(image, mask)` tuple and expects a float image.\n\n```python\nfrom openpiv import preprocess\n\n# method=\"edges\" for dark, sharp-edged objects; \"intensity\" for high-contrast objects.\nframe_a_masked, mask_a = preprocess.dynamic_masking(\n    frame_a.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\nframe_b_masked, mask_b = preprocess.dynamic_masking(\n    frame_b.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\n```\n\nFeed the **returned image** into the correlation step — it already has the masked region zeroed. Do\nnot multiply the original frame by `mask`: masking is already applied, and for `method=\"edges\"` the\nmask comes back as `uint8` 0\u002F255 rather than boolean, so multiplying rescales the image by 255.\n\n### Multi-Pass Processing\n\nMulti-pass (window deformation) lives in `openpiv.windef`, driven by a `PIVSettings` dataclass.\n`pyprocess` has no multi-pass entry point.\n\n```python\nimport numpy as np\nfrom openpiv import scaling, windef\n\nsettings = windef.PIVSettings()\nsettings.windowsizes = (64, 32, 16)   # one entry per pass, decreasing (this is also the default)\nsettings.overlap = (32, 16, 8)        # same length as windowsizes\nsettings.num_iterations = 3           # number of passes to actually run\nsettings.sig2noise_threshold = 1.05\n\nx, y, u, v, flags = windef.simple_multipass(\n    frame_a.astype(np.int32), frame_b.astype(np.int32), settings\n)\n\n# Output is in PIXELS PER FRAME -- convert yourself. scaling.uniform only divides\n# by scaling_factor, so apply dt separately.\ndt = 0.02\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nu, v = u \u002F dt, v \u002F dt\n```\n\n`simple_multipass` already validates, replaces outliers, fills remaining NaNs with zeros, and calls\n`transform_coordinates` — do not repeat those steps.\n\n**Units trap:** `PIVSettings` has `dt` and `scaling_factor` fields, but `windef` never uses either —\n`first_pass` calls `extended_search_area_piv` without `dt`, so the whole multi-pass chain works in\npixels per frame. Setting `settings.dt = 0.02` changes nothing about the returned values. Convert\nafter the fact, as above.\n\nFor control over individual passes, `windef.first_pass` and `windef.multipass_img_deform` are the\nlower-level building blocks.\n\n## Validation and Post-Processing\n\n### Validation Methods\n\nEvery validator returns a boolean array where **True marks a spurious vector**.\n\n```python\n# Signal-to-noise\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n\n# Global range -- takes (min, max) TUPLES, positionally or as u_thresholds\u002Fv_thresholds.\nflags = validation.global_val(u, v, (-300, 300), (-300, 300))\n\n# Local median -- u_threshold and v_threshold are REQUIRED; size is the neighbourhood half-width.\nflags = validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0, size=1)\n\n# Combine with boolean OR (not np.maximum -- these are bool arrays).\nflags = (\n    validation.sig2noise_val(s2n, threshold=1.05)\n    | validation.global_val(u, v, (-300, 300), (-300, 300))\n    | validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0)\n)\n```\n\n**Set these thresholds in the units of `u` and `v`, not in pixels per frame.**\n`extended_search_area_piv` divides by `dt`, so with `dt=0.02` a 3 px\u002Fframe displacement arrives as\n150 px\u002Fs. The thresholds above suit that case; the `(-30, 30)` figure that PIV literature and\n`PIVSettings.min_max_u_disp` use is a px\u002Fframe limit, and applying it to px\u002Fs output rejects the\nentire field. Either validate before scaling, or scale the thresholds by `1\u002Fdt` too.\n\n### Outlier Replacement\n\n```python\nu, v = filters.replace_outliers(\n    u, v, flags, method=\"localmean\", max_iter=3, tol=1e-3, kernel_size=2\n)\n```\n\n`method` accepts `\"localmean\"`, `\"disk\"`, or `\"distance\"` — and only those three. An unrecognized\nname is not rejected; it falls through to an all-zero kernel and silently returns a useless field.\nNote that replacement *fills* the flagged\npositions with interpolated values — if you then overwrite them with NaN, the replacement was\nwasted. Choose one or the other:\n\n```python\n# Keep flagged vectors out of the analysis entirely, instead of interpolating them.\nu = np.where(flags, np.nan, u)\nv = np.where(flags, np.nan, v)\n```\n\n### Smoothing\n\nSmoothing is `openpiv.smoothn.smoothn`; there is no `openpiv.smooth` module. It returns a tuple\nwhose first element is the smoothed field, and it does not accept NaN input.\n\n```python\nfrom openpiv.smoothn import smoothn\n\nu_smooth, *_ = smoothn(np.nan_to_num(u), s=0.5)  # s: larger == smoother\nv_smooth, *_ = smoothn(np.nan_to_num(v), s=0.5)\nu_smooth = np.asarray(u_smooth)\n```\n\n## Visualization\n\n### Vector Field Plotting\n\n`display_vector_field` reads a saved vectors file and calls `plt.show()` internally, so select a\nnon-interactive backend for batch runs.\n\n```python\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport matplotlib.pyplot as plt\nfrom openpiv import tools\n\nfig, ax = plt.subplots(figsize=(8, 8))\ntools.display_vector_field(\n    \"vectors.txt\",\n    ax=ax,\n    scaling_factor=96.52,   # same factor used in scaling.uniform, to map back onto the image\n    scale=50,\n    width=0.0035,\n    on_img=True,\n    image_name=\"frame_a.bmp\",\n)\nfig.savefig(\"vector_field.png\", dpi=150, bbox_inches=\"tight\")\nplt.close(fig)\n```\n\n### Custom Visualization\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\nmag = np.sqrt(u**2 + v**2)\nfor ax, field, title, cmap in [\n    (axes[0], mag, \"Velocity Magnitude\", \"viridis\"),\n    (axes[1], u, \"U Velocity\", \"RdBu_r\"),\n    (axes[2], v, \"V Velocity\", \"RdBu_r\"),\n]:\n    im = ax.imshow(field, cmap=cmap)\n    ax.set_title(title)\n    plt.colorbar(im, ax=ax)\n\nfig.tight_layout()\nfig.savefig(\"velocity_components.png\")\nplt.close(fig)\n```\n\n## Analysis Functions\n\n`scripts\u002Fanalyze.py` bundles these against a `params.npz` written by `runner.py`. It infers the\nphysical grid spacing from the saved coordinates, so the derivatives come out per unit length:\n\n```python\nimport sys\nsys.path.insert(0, \"skills\u002Fopenpiv\u002Fscripts\")\nfrom analyze import PIVAnalyzer\n\npiv = PIVAnalyzer(\"results\u002Fparams.npz\")\nvorticity = piv.compute_vorticity()          # dv\u002Fdx - du\u002Fdy\nexx, eyy, exy = piv.compute_strain()\nstats = piv.compute_statistics()             # u_mean, v_mean, rms_u, rms_v, tke\npiv.plot_vector_field(save_path=\"quiver.png\")\n```\n\nThe standalone forms, if you would rather compute them inline:\n\n### Vorticity\n\n```python\ndef compute_vorticity(u, v, dx=1.0, dy=None):\n    \"\"\"Out-of-plane vorticity dv\u002Fdx - du\u002Fdy. Pass the physical grid spacing, not 1.0.\"\"\"\n    dy = dx if dy is None else dy\n    return np.gradient(v, dx, axis=1) - np.gradient(u, dy, axis=0)\n```\n\nThe grid spacing is `(window_size - overlap) \u002F scaling_factor` in physical units, so leaving `dx=1.0`\nyields vorticity per grid cell, not per unit length.\n\n**Sign convention:** `runner.py` ends with `transform_coordinates`, which relabels the grid into a\nright-handed y-up frame but leaves the rows in image order, so the saved `y` *decreases* as the row\nindex grows. The standalone forms above assume the opposite, so on a `params.npz` field they return\n`-du\u002Fdy` and flip the sign of the vorticity and the shear strain — negate the `axis=0` derivatives, or\nuse `PIVAnalyzer`, which reads the orientation off the saved coordinates.\n\n### Strain Rate\n\n```python\ndef compute_strain(u, v, dx=1.0, dy=None):\n    \"\"\"Return (exx, eyy, exy) of the 2D strain-rate tensor.\"\"\"\n    dy = dx if dy is None else dy\n    du_dx = np.gradient(u, dx, axis=1)\n    du_dy = np.gradient(u, dy, axis=0)\n    dv_dx = np.gradient(v, dx, axis=1)\n    dv_dy = np.gradient(v, dy, axis=0)\n    return du_dx, dv_dy, 0.5 * (du_dy + dv_dx)\n```\n\n### Turbulence Statistics\n\n```python\ndef compute_statistics(u, v):\n    \"\"\"Single-frame spatial statistics. NOT Reynolds decomposition.\"\"\"\n    u_prime = u - np.nanmean(u)\n    v_prime = v - np.nanmean(v)\n    rms_u, rms_v = np.nanstd(u_prime), np.nanstd(v_prime)\n    return {\n        \"u_mean\": np.nanmean(u),\n        \"v_mean\": np.nanmean(v),\n        \"rms_u\": rms_u,\n        \"rms_v\": rms_v,\n        \"tke\": 0.5 * (rms_u**2 + rms_v**2),\n    }\n```\n\n**Caveat:** subtracting the *spatial* mean of one frame measures spatial variance, which equals\nturbulent intensity only for a homogeneous field. Genuine Reynolds decomposition needs an ensemble of\nimage pairs: average over the time axis, then subtract that mean field from each realization.\n\n## CLI Usage\n\n```bash\n# Basic run\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image img1.bmp --image img2.bmp --output_dir results --verbose\n\n# Tuned parameters with dynamic masking\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp \\\n    --image frame_b.bmp \\\n    --output_dir results \\\n    --window_size 32 \\\n    --overlap 12 \\\n    --search_area 38 \\\n    --dt 0.02 \\\n    --scaling 96.52 \\\n    --threshold 1.05 \\\n    --mask dynamic \\\n    --mask_method intensity \\\n    --verbose\n```\n\n### CLI Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `--image` | required | Image file; specify exactly twice for the pair |\n| `--output_dir` | `results` | Output directory (created if absent) |\n| `--window_size` | 32 | Interrogation window size (px) |\n| `--overlap` | 12 | Window overlap (px) |\n| `--search_area` | 38 | Search area size (px), must be ≥ `--window_size` |\n| `--dt` | 0.02 | Time between frames (s) |\n| `--scaling` | 96.52 | Scaling factor, pixels per physical unit (e.g. px\u002Fmm) |\n| `--threshold` | 1.05 | `peak2peak` signal-to-noise threshold |\n| `--mask` | `none` | `none` or `dynamic` (`openpiv.preprocess.dynamic_masking`) |\n| `--mask_method` | `intensity` | `edges` or `intensity`, used only with `--mask dynamic` |\n| `--drop_invalid` | off | NaN out flagged vectors instead of keeping interpolated values |\n| `--verbose` | off | Print progress messages |\n\nVerify an install end to end against OpenPIV's own bundled image pair:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frun_example.py --output_dir \u002Ftmp\u002Fopenpiv-demo\n```\n\n## Output Files\n\n- **vectors.txt** — tab-delimited, `%.4e` formatted, with a `# x y u v flags mask` comment header\n- **params.npz** — NumPy archive with `x`, `y`, `u`, `v`, `flags` arrays\n- **vector_field.png** — vector field drawn over the first frame\n\n```text\n# x\ty\tu\tv\tflags\tmask\n2.1757e-01\t3.5226e+00\t-6.2220e-02\t-2.7081e+00\t0.0000e+00\t0.0000e+00\n4.8695e-01\t3.5226e+00\t-3.1587e-01\t-2.9800e+00\t0.0000e+00\t0.0000e+00\n```\n\n`flags` is written as a float, `0` for a valid vector and `1` for a flagged one.\n\n## Best Practices\n\n### Parameter Selection\n\n1. **Window size** — 32×32 suits most cases. 64\u002F128 for better correlation at coarser resolution;\n   16\u002F24 for finer resolution at the cost of noise.\n2. **Overlap** — 50–75% of window size.\n3. **Threshold** — raise it to reject more vectors; always re-tune after switching\n   `sig2noise_method`.\n4. **Scaling factor** — calibrate against a known reference such as a calibration grid, and keep the\n   units straight (`96.52` in OpenPIV's `test1` tutorial data is px\u002Fmm).\n\n### Image Quality\n\n- Particles visible and evenly distributed, 5–10 per interrogation window\n- No saturated or overexposed regions\n- Minimal background noise; consider background subtraction across a run\n\n### Processing Tips\n\n1. Start from the defaults, then tune against the vector field you get.\n2. Inspect the `s2n` distribution — a low median means poor correlation, not a bad threshold.\n3. Visualize early; obvious problems (uniform vectors, edge artifacts) show up immediately.\n4. Use multi-pass (`windef`) for flows with large velocity gradients or displacements.\n5. Mask reflections and solid boundaries rather than letting them generate vectors.\n\n## Resources\n\n### references\u002F\n\n- `advanced_algorithms.md` — correlation and subpixel methods, multi-pass window deformation,\n  `PIVSettings` fields, 3D and phase-separation modules\n\nLoad the reference when detailed algorithm or settings information is needed.\n\n## Related skills\n\n- `scvelo`: Performs RNA velocity analysis with scVelo on single-cell RNA-seq AnnData objects that have spliced and unspliced layers (from velocyto, ST…\n","# OpenPIV\n\n## Overview\n\nOpenPIV (Open Particle Image Velocimetry) analyzes fluid flow from PIV image pairs. It covers\npreprocessing, cross-correlation, vector validation, outlier replacement, smoothing, and scaling to\nphysical units.\n\nEverything below is verified against **openpiv 0.25.4**. The API moves between releases — check\n`inspect.signature()` before trusting a snippet against a different version.\n\n## When to use\n\nUse this skill when working with experimental PIV or flow-visualization image pairs: measuring 2D\nvelocity fields, tuning interrogation-window parameters, validating vectors, or deriving vorticity,\nstrain rate, and turbulence statistics. For *simulating* flow rather than measuring it, use a CFD\nskill instead.\n\n## Quick Start\n\nInstall OpenPIV:\n\n```bash\nuv pip install openpiv\n\n# Pin it when the analysis needs to be reproducible -- this is the version every\n# snippet below was checked against.\nuv pip install \"openpiv==0.25.4\"\n```\n\nRun PIV analysis on an image pair:\n\n```python\nimport numpy as np\nfrom openpiv import tools, pyprocess, validation, filters, scaling\n\nframe_a = tools.imread(\"image_a.bmp\")\nframe_b = tools.imread(\"image_b.bmp\")\n\n# Cross-correlate. Returns (u, v, s2n) whenever sig2noise_method is not None.\nu, v, s2n = pyprocess.extended_search_area_piv(\n    frame_a.astype(np.int32),\n    frame_b.astype(np.int32),\n    window_size=32,\n    overlap=12,\n    dt=0.02,\n    search_area_size=38,\n    correlation_method=\"linear\",   # required for search_area_size > window_size\n    sig2noise_method=\"peak2peak\",\n)\n\nx, y = pyprocess.get_coordinates(\n    image_size=frame_a.shape,\n    search_area_size=38,\n    overlap=12,\n)\n\n# flags is a boolean array: True marks a spurious vector.\nflags = validation.sig2noise_val(s2n, threshold=1.05)\nu, v = filters.replace_outliers(u, v, flags, method=\"localmean\", max_iter=3, kernel_size=2)\n\n# Scale to physical units, then flip to image coordinates for plotting.\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nx, y, u, v = tools.transform_coordinates(x, y, u, v)\n\ntools.save(\"vectors.txt\", x, y, u, v, flags)\n```\n\nOr use the bundled CLI, which wraps exactly that pipeline:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp --image frame_b.bmp --output_dir results --verbose\n```\n\n## Core Concepts\n\n### PIV Fundamentals\n\nParticle Image Velocimetry is an optical method for measuring fluid velocity by tracking illuminated\ntracer particles between two images.\n\n**Process flow:**\n\n1. Capture an image pair (`frame_a`, `frame_b`) separated by a known time `dt`.\n2. Divide the images into interrogation windows.\n3. Cross-correlate matching windows to find peak displacement.\n4. Validate vectors (signal-to-noise, global range, local median).\n5. Replace spurious vectors with interpolated values.\n6. Scale pixel displacements to physical units.\n\n### Interrogation Window Parameters\n\n**`window_size`** — correlation window in pixels (typically 16–128). Larger windows give better\ncorrelation but coarser spatial resolution.\n\n**`overlap`** — pixels shared between adjacent windows (typically 50–75% of `window_size`). Higher\noverlap raises vector density and cost, but adjacent vectors become correlated rather than\nindependent.\n\n**`search_area_size`** — the window searched in the second frame. Must be ≥ `window_size`; a few\npixels larger accommodates larger displacements. Pair an extended search area with\n`correlation_method=\"linear\"` — the default `\"circular\"` relies on FFT wrap-around and aliases large\ndisplacements into small ones. See `references\u002Fadvanced_algorithms.md`.\n\nRules of thumb: keep the largest displacement under about a quarter of `window_size`, and aim for\n5–10 particles per window.\n\n### Signal-to-Noise Ratio\n\n`s2n` measures how distinct the correlation peak is. `sig2noise_method` controls how it is computed —\n`\"peak2mean\"` (the function default) or `\"peak2peak\"`. **The two are on different scales**, so a\nthreshold tuned for one is meaningless for the other. Typical `peak2peak` thresholds are 1.05–1.3.\n\n```python\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n# flags is bool: True == spurious. `~flags` selects the good vectors.\n```\n\n## Common Operations\n\n### Dynamic Masking\n\nMasking lives in `openpiv.preprocess`, **not** in an `openpiv.masking` module. It returns an\n`(image, mask)` tuple and expects a float image.\n\n```python\nfrom openpiv import preprocess\n\n# method=\"edges\" for dark, sharp-edged objects; \"intensity\" for high-contrast objects.\nframe_a_masked, mask_a = preprocess.dynamic_masking(\n    frame_a.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\nframe_b_masked, mask_b = preprocess.dynamic_masking(\n    frame_b.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\n```\n\nFeed the **returned image** into the correlation step — it already has the masked region zeroed. Do\nnot multiply the original frame by `mask`: masking is already applied, and for `method=\"edges\"` the\nmask comes back as `uint8` 0\u002F255 rather than boolean, so multiplying rescales the image by 255.\n\n### Multi-Pass Processing\n\nMulti-pass (window deformation) lives in `openpiv.windef`, driven by a `PIVSettings` dataclass.\n`pyprocess` has no multi-pass entry point.\n\n```python\nimport numpy as np\nfrom openpiv import scaling, windef\n\nsettings = windef.PIVSettings()\nsettings.windowsizes = (64, 32, 16)   # one entry per pass, decreasing (this is also the default)\nsettings.overlap = (32, 16, 8)        # same length as windowsizes\nsettings.num_iterations = 3           # number of passes to actually run\nsettings.sig2noise_threshold = 1.05\n\nx, y, u, v, flags = windef.simple_multipass(\n    frame_a.astype(np.int32), frame_b.astype(np.int32), settings\n)\n\n# Output is in PIXELS PER FRAME -- convert yourself. scaling.uniform only divides\n# by scaling_factor, so apply dt separately.\ndt = 0.02\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nu, v = u \u002F dt, v \u002F dt\n```\n\n`simple_multipass` already validates, replaces outliers, fills remaining NaNs with zeros, and calls\n`transform_coordinates` — do not repeat those steps.\n\n**Units trap:** `PIVSettings` has `dt` and `scaling_factor` fields, but `windef` never uses either —\n`first_pass` calls `extended_search_area_piv` without `dt`, so the whole multi-pass chain works in\npixels per frame. Setting `settings.dt = 0.02` changes nothing about the returned values. Convert\nafter the fact, as above.\n\nFor control over individual passes, `windef.first_pass` and `windef.multipass_img_deform` are the\nlower-level building blocks.\n\n## Validation and Post-Processing\n\n### Validation Methods\n\nEvery validator returns a boolean array where **True marks a spurious vector**.\n\n```python\n# Signal-to-noise\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n\n# Global range -- takes (min, max) TUPLES, positionally or as u_thresholds\u002Fv_thresholds.\nflags = validation.global_val(u, v, (-300, 300), (-300, 300))\n\n# Local median -- u_threshold and v_threshold are REQUIRED; size is the neighbourhood half-width.\nflags = validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0, size=1)\n\n# Combine with boolean OR (not np.maximum -- these are bool arrays).\nflags = (\n    validation.sig2noise_val(s2n, threshold=1.05)\n    | validation.global_val(u, v, (-300, 300), (-300, 300))\n    | validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0)\n)\n```\n\n**Set these thresholds in the units of `u` and `v`, not in pixels per frame.**\n`extended_search_area_piv` divides by `dt`, so with `dt=0.02` a 3 px\u002Fframe displacement arrives as\n150 px\u002Fs. The thresholds above suit that case; the `(-30, 30)` figure that PIV literature and\n`PIVSettings.min_max_u_disp` use is a px\u002Fframe limit, and applying it to px\u002Fs output rejects the\nentire field. Either validate before scaling, or scale the thresholds by `1\u002Fdt` too.\n\n### Outlier Replacement\n\n```python\nu, v = filters.replace_outliers(\n    u, v, flags, method=\"localmean\", max_iter=3, tol=1e-3, kernel_size=2\n)\n```\n\n`method` accepts `\"localmean\"`, `\"disk\"`, or `\"distance\"` — and only those three. An unrecognized\nname is not rejected; it falls through to an all-zero kernel and silently returns a useless field.\nNote that replacement *fills* the flagged\npositions with interpolated values — if you then overwrite them with NaN, the replacement was\nwasted. Choose one or the other:\n\n```python\n# Keep flagged vectors out of the analysis entirely, instead of interpolating them.\nu = np.where(flags, np.nan, u)\nv = np.where(flags, np.nan, v)\n```\n\n### Smoothing\n\nSmoothing is `openpiv.smoothn.smoothn`; there is no `openpiv.smooth` module. It returns a tuple\nwhose first element is the smoothed field, and it does not accept NaN input.\n\n```python\nfrom openpiv.smoothn import smoothn\n\nu_smooth, *_ = smoothn(np.nan_to_num(u), s=0.5)  # s: larger == smoother\nv_smooth, *_ = smoothn(np.nan_to_num(v), s=0.5)\nu_smooth = np.asarray(u_smooth)\n```\n\n## Visualization\n\n### Vector Field Plotting\n\n`display_vector_field` reads a saved vectors file and calls `plt.show()` internally, so select a\nnon-interactive backend for batch runs.\n\n```python\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport matplotlib.pyplot as plt\nfrom openpiv import tools\n\nfig, ax = plt.subplots(figsize=(8, 8))\ntools.display_vector_field(\n    \"vectors.txt\",\n    ax=ax,\n    scaling_factor=96.52,   # same factor used in scaling.uniform, to map back onto the image\n    scale=50,\n    width=0.0035,\n    on_img=True,\n    image_name=\"frame_a.bmp\",\n)\nfig.savefig(\"vector_field.png\", dpi=150, bbox_inches=\"tight\")\nplt.close(fig)\n```\n\n### Custom Visualization\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\nmag = np.sqrt(u**2 + v**2)\nfor ax, field, title, cmap in [\n    (axes[0], mag, \"Velocity Magnitude\", \"viridis\"),\n    (axes[1], u, \"U Velocity\", \"RdBu_r\"),\n    (axes[2], v, \"V Velocity\", \"RdBu_r\"),\n]:\n    im = ax.imshow(field, cmap=cmap)\n    ax.set_title(title)\n    plt.colorbar(im, ax=ax)\n\nfig.tight_layout()\nfig.savefig(\"velocity_components.png\")\nplt.close(fig)\n```\n\n## Analysis Functions\n\n`scripts\u002Fanalyze.py` bundles these against a `params.npz` written by `runner.py`. It infers the\nphysical grid spacing from the saved coordinates, so the derivatives come out per unit length:\n\n```python\nimport sys\nsys.path.insert(0, \"skills\u002Fopenpiv\u002Fscripts\")\nfrom analyze import PIVAnalyzer\n\npiv = PIVAnalyzer(\"results\u002Fparams.npz\")\nvorticity = piv.compute_vorticity()          # dv\u002Fdx - du\u002Fdy\nexx, eyy, exy = piv.compute_strain()\nstats = piv.compute_statistics()             # u_mean, v_mean, rms_u, rms_v, tke\npiv.plot_vector_field(save_path=\"quiver.png\")\n```\n\nThe standalone forms, if you would rather compute them inline:\n\n### Vorticity\n\n```python\ndef compute_vorticity(u, v, dx=1.0, dy=None):\n    \"\"\"Out-of-plane vorticity dv\u002Fdx - du\u002Fdy. Pass the physical grid spacing, not 1.0.\"\"\"\n    dy = dx if dy is None else dy\n    return np.gradient(v, dx, axis=1) - np.gradient(u, dy, axis=0)\n```\n\nThe grid spacing is `(window_size - overlap) \u002F scaling_factor` in physical units, so leaving `dx=1.0`\nyields vorticity per grid cell, not per unit length.\n\n**Sign convention:** `runner.py` ends with `transform_coordinates`, which relabels the grid into a\nright-handed y-up frame but leaves the rows in image order, so the saved `y` *decreases* as the row\nindex grows. The standalone forms above assume the opposite, so on a `params.npz` field they return\n`-du\u002Fdy` and flip the sign of the vorticity and the shear strain — negate the `axis=0` derivatives, or\nuse `PIVAnalyzer`, which reads the orientation off the saved coordinates.\n\n### Strain Rate\n\n```python\ndef compute_strain(u, v, dx=1.0, dy=None):\n    \"\"\"Return (exx, eyy, exy) of the 2D strain-rate tensor.\"\"\"\n    dy = dx if dy is None else dy\n    du_dx = np.gradient(u, dx, axis=1)\n    du_dy = np.gradient(u, dy, axis=0)\n    dv_dx = np.gradient(v, dx, axis=1)\n    dv_dy = np.gradient(v, dy, axis=0)\n    return du_dx, dv_dy, 0.5 * (du_dy + dv_dx)\n```\n\n### Turbulence Statistics\n\n```python\ndef compute_statistics(u, v):\n    \"\"\"Single-frame spatial statistics. NOT Reynolds decomposition.\"\"\"\n    u_prime = u - np.nanmean(u)\n    v_prime = v - np.nanmean(v)\n    rms_u, rms_v = np.nanstd(u_prime), np.nanstd(v_prime)\n    return {\n        \"u_mean\": np.nanmean(u),\n        \"v_mean\": np.nanmean(v),\n        \"rms_u\": rms_u,\n        \"rms_v\": rms_v,\n        \"tke\": 0.5 * (rms_u**2 + rms_v**2),\n    }\n```\n\n**Caveat:** subtracting the *spatial* mean of one frame measures spatial variance, which equals\nturbulent intensity only for a homogeneous field. Genuine Reynolds decomposition needs an ensemble of\nimage pairs: average over the time axis, then subtract that mean field from each realization.\n\n## CLI Usage\n\n```bash\n# Basic run\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image img1.bmp --image img2.bmp --output_dir results --verbose\n\n# Tuned parameters with dynamic masking\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp \\\n    --image frame_b.bmp \\\n    --output_dir results \\\n    --window_size 32 \\\n    --overlap 12 \\\n    --search_area 38 \\\n    --dt 0.02 \\\n    --scaling 96.52 \\\n    --threshold 1.05 \\\n    --mask dynamic \\\n    --mask_method intensity \\\n    --verbose\n```\n\n### CLI Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `--image` | required | Image file; specify exactly twice for the pair |\n| `--output_dir` | `results` | Output directory (created if absent) |\n| `--window_size` | 32 | Interrogation window size (px) |\n| `--overlap` | 12 | Window overlap (px) |\n| `--search_area` | 38 | Search area size (px), must be ≥ `--window_size` |\n| `--dt` | 0.02 | Time between frames (s) |\n| `--scaling` | 96.52 | Scaling factor, pixels per physical unit (e.g. px\u002Fmm) |\n| `--threshold` | 1.05 | `peak2peak` signal-to-noise threshold |\n| `--mask` | `none` | `none` or `dynamic` (`openpiv.preprocess.dynamic_masking`) |\n| `--mask_method` | `intensity` | `edges` or `intensity`, used only with `--mask dynamic` |\n| `--drop_invalid` | off | NaN out flagged vectors instead of keeping interpolated values |\n| `--verbose` | off | Print progress messages |\n\nVerify an install end to end against OpenPIV's own bundled image pair:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frun_example.py --output_dir \u002Ftmp\u002Fopenpiv-demo\n```\n\n## Output Files\n\n- **vectors.txt** — tab-delimited, `%.4e` formatted, with a `# x y u v flags mask` comment header\n- **params.npz** — NumPy archive with `x`, `y`, `u`, `v`, `flags` arrays\n- **vector_field.png** — vector field drawn over the first frame\n\n```text\n# x\ty\tu\tv\tflags\tmask\n2.1757e-01\t3.5226e+00\t-6.2220e-02\t-2.7081e+00\t0.0000e+00\t0.0000e+00\n4.8695e-01\t3.5226e+00\t-3.1587e-01\t-2.9800e+00\t0.0000e+00\t0.0000e+00\n```\n\n`flags` is written as a float, `0` for a valid vector and `1` for a flagged one.\n\n## Best Practices\n\n### Parameter Selection\n\n1. **Window size** — 32×32 suits most cases. 64\u002F128 for better correlation at coarser resolution;\n   16\u002F24 for finer resolution at the cost of noise.\n2. **Overlap** — 50–75% of window size.\n3. **Threshold** — raise it to reject more vectors; always re-tune after switching\n   `sig2noise_method`.\n4. **Scaling factor** — calibrate against a known reference such as a calibration grid, and keep the\n   units straight (`96.52` in OpenPIV's `test1` tutorial data is px\u002Fmm).\n\n### Image Quality\n\n- Particles visible and evenly distributed, 5–10 per interrogation window\n- No saturated or overexposed regions\n- Minimal background noise; consider background subtraction across a run\n\n### Processing Tips\n\n1. Start from the defaults, then tune against the vector field you get.\n2. Inspect the `s2n` distribution — a low median means poor correlation, not a bad threshold.\n3. Visualize early; obvious problems (uniform vectors, edge artifacts) show up immediately.\n4. Use multi-pass (`windef`) for flows with large velocity gradients or displacements.\n5. Mask reflections and solid boundaries rather than letting them generate vectors.\n\n## Resources\n\n### references\u002F\n\n- `advanced_algorithms.md` — correlation and subpixel methods, multi-pass window deformation,\n  `PIVSettings` fields, 3D and phase-separation modules\n\nLoad the reference when detailed algorithm or settings information is needed.\n\n## Related skills\n\n- `scvelo`: Performs RNA velocity analysis with scVelo on single-cell RNA-seq AnnData objects that have spliced and unspliced layers (from velocyto, ST…\n",{"name":5,"license":15,"metadata":52,"description":7,"allowed-tools":59,"compatibility":60},{"tags":53,"version":54,"category":55,"maintainer":56,"contributor":57,"tested-against":58},"particle image velocimetry, PIV, fluid dynamics, flow visualization, physics","1.1","physical-sciences","Kalaris Labs","OpenPIV Team","openpiv 0.25.4","Read Write Edit Bash","Requires Python 3.10+ with openpiv installed (uv pip install openpiv). numpy, scipy, scikit-image, and matplotlib arrive as dependencies. No network access needed after install.","main","2b63f856ce19c2a797929cacabd9e0fc936812fa","plugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv",474,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins","https:\u002F\u002Fhol.org\u002Fplugins\u002Fbest-codex-plugins","https:\u002F\u002Fgithub.com\u002Fhashgraph-online","https:\u002F\u002Fhol.org","Open-source standards and developer tools for interoperable AI agents: discovery, identity, communication, payments, privacy and security.","2026-11-11 14:40:14",{"source":8,"skillName":5,"commands":72,"prompt":82,"zipAvailable":83},[73,76,79],{"tool":74,"command":75},"npx","npx skills add hashgraph-online\u002Fawesome-codex-plugins --skill openpiv",{"tool":77,"command":78},"bunx","bunx skills add hashgraph-online\u002Fawesome-codex-plugins --skill openpiv",{"tool":80,"command":81},"pnpm","pnpm dlx skills add hashgraph-online\u002Fawesome-codex-plugins --skill openpiv","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002FSKILL.md",true,[85,91,97,101,105],{"path":86,"resourceType":87,"resourceTypeDesc":88,"sizeBytes":89,"sourceHtmlUrl":90},"references\u002Fadvanced_algorithms.md","REFERENCE","参考文档",10669,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002Freferences\u002Fadvanced_algorithms.md",{"path":92,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":95,"sourceHtmlUrl":96},"scripts\u002F__init__.py","SCRIPT","脚本",29,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002Fscripts\u002F__init__.py",{"path":98,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":99,"sourceHtmlUrl":100},"scripts\u002Fanalyze.py",5628,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002Fscripts\u002Fanalyze.py",{"path":102,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":103,"sourceHtmlUrl":104},"scripts\u002Frun_example.py",3076,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002Fscripts\u002Frun_example.py",{"path":106,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":107,"sourceHtmlUrl":108},"scripts\u002Frunner.py",6848,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FKalarisLabs\u002Fresearch-agent-skills\u002Fskills\u002Fopenpiv\u002Fscripts\u002Frunner.py",[110,119,126,133,159,184],{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":118},"01M746ZWACVKMZ1BJXJZHYJSSX","migrate-to-e2e","Moves an existing Playwright, Cypress, Selenium, Appium, Detox, Maestro, or TesterArmy suite to e2e one slice at a time, with the old suite running beside the new one until each ported test is proven. Keeps a MIGRATION.md progress file so any later session resumes where the last stopped. Optionally plants a defect to show both suites catch it. Use for \u002Fmigrate-to-e2e, \"migrate our tests to e2e\", \"port these Maestro flows\", \"move our TesterArmy tests\", or when a project has an e2e config and an older suite still running.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fmigrate-to-e2e\u002FSKILL.md",[],[],"2026-11-11 15:11:14",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":118},"01M746ZPTAX1Q0FBKAB1CYND7E","e2e","Writes, runs, and debugs end-to-end tests for web and mobile apps with e2e, the agentic test runner, which mixes agent.act goals with exact locator assertions on a Playwright browser or an iOS or Android device. Also drives a project's running app live over the e2e MCP server to look at a screen, check a UI change, take a screenshot or record a video, and try a locator; and runs bug bashes, parallel e2e explore runs with each bug proven by a repro test. Use when a project depends on e2e or has an e2e.config.ts, when asked for end-to-end, browser, mobile, or agentic UI tests, to check a change in the running app, to QA or bug bash an app or branch, or when an e2e run fails.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fe2e\u002FSKILL.md",[],[],{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":118},"01M746ZJN784HVHMDP9MQGCSGG","create-verification-skill","Generate a project-local verify-\u003Capp> skill on top of e2e, so any coding agent can launch the app, check it is worth driving, exercise a feature the way a user does, keep evidence, and bug bash it. Writes the skill, a feature map with one explore charter per feature, and proves it once. Use for \u002Fcreate-verification-skill, \"make a verification skill for this repo\", or when a project has no scripted way to prove UI behavior.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fcreate-verification-skill\u002FSKILL.md",[],[],{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":47},"01M716A6ETNB9B1SQ3GXZC75VR","deja-search","deja-vu memory — search the user's past AI coding sessions with the deja CLI. Holds what they already settled and never wrote into the repo (naming rules, banned or already-tried tools, required checks before merge, preferred values, who owns what). Use before your first edit in a task, before you call a change done or ready to merge, before you recommend a tool, library, design or reviewer, before re-debugging an error that may already be solved, when they say 'didn't we fix this before', 'what did we decide about X' or 'I already have that', and before telling them something on this machine does not exist.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fvshulcz\u002Fdeja-vu\u002Fskills\u002Fdeja-search\u002FSKILL.md",[],[140,141,142,143,144,145,146,147,148,149,150,28,151,152,153,154,155,156,157,158],"search","deja search","never","error","ready","memory","re","decide","fix","design","debugging","you","done","reviewer","io","change","cli","merge","past",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":163,"categories":164,"keywords":165,"publishedAt":47},"01M716A3J2W5SENSE9VGMXB375","deja-reflect","End-of-session reflection and memory curation with deja-vu. Review what was decided, what commands broke and what repaired them, and record durable project rules or decisions with deja remember so the next session starts with them.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fvshulcz\u002Fdeja-vu\u002Fskills\u002Fdeja-reflect\u002FSKILL.md",[],[166,167,168,154,169,170,171,172,173,174,175,176,177,178,145,179,180,181,182,183],"deja reflect","reflect","review","with","record","github","next","https","node","Rules","decisions","brew","remember","project rules","project","session","end","reflection",{"skillNo":185,"name":186,"nameZh":6,"description":187,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":114,"licenseFileUrl":6,"sourceHtmlUrl":188,"categories":189,"keywords":197,"publishedAt":47},"01M715T3RR4BAYSR57HPPTJ0PF","revid","Make, edit, export and post AI videos with Revid (revid.ai) through the Revid MCP server. Use whenever the user wants a short-form or long-form video made (from an idea, a script, a URL, an article, a PDF, a tweet, a product page, their own clips, or a song), wants to find what is going viral on TikTok, YouTube, Instagram or X before making something, wants to edit or re-export an existing Revid project, generate a standalone AI image or clip, make a series episode, or publish and schedule a finished video to connected social accounts. Covers setup (hosted MCP with OAuth, or an API key), the 36 tools, credits, polling and the rules for publishing. Routes to the more specific revid-* skills when one fits.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftmakersas\u002Frevid-skills\u002Fskills\u002Frevid\u002FSKILL.md",[190,191,194],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":192,"categoryName":193,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":195,"categoryName":196,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",[186,198,199,200,201,202,203,180,204,146,205,206,207,208,28,37,209,210,211,212],"URL","Video","short-form","standalone","PDF","viral","tiktok","short","social","MCP","song","mcp server","schedule","api","publish"]