AGENT SKILL

audio-loop

Prepare an existing audio bed for website looping: normalize loudness, optionally balance stereo, encode FLAC and provide Web Audio playback. Use for web ambience or loop-boundary diagnosis; source discontinuities require separate editing.

适用职业开发工程师
使用场景图像与多媒体
License 许可
MIT
最近更新
2026-11-11
Stars
★ 5
Forks
0

01 前言 Front Matter

name
audio-loop
license
MIT
metadata
{ "author": "coroboros", "sources": "ffmpeg.org; developer.mozilla.org/docs/Web/API/Web_Audio_API" }
description
Prepare an existing audio bed for website looping: normalize loudness, optionally balance stereo, encode FLAC and provide Web Audio playback. Use for web ambience or loop-boundary diagnosis; source discontinuities require separate editing.
when_to_use
When the user has an audio clip that needs to loop without audible artifacts on a web page, or when `<audio loop>` is producing an audible gap or tick at each iteration. Keywords — audio, loop, ambient, hero, background, breeze, wind, rain, atmosphere, soundscape, seamless, gapless, flac, web audio, loudness, lufs, normalize, stereo balance, ffmpeg. For video loops use `/video-loop` (sibling — parallel architecture, crossfade + MP4/WebM encode). Skip for composing, mixing, or mastering music/podcasts, and for transcription — looping an existing music bed for a page stays in scope.
allowed-tools
Bash(ffmpeg *) Bash(ffprobe *) Bash(command *) Bash(bash *) Bash(stat *) Read
argument-hint
<input.wav> [options] — e.g. /audio-loop breeze.wav -t -28
compatibility
Requires bash, FFmpeg and ffprobe for local encoding. Playback verification requires a browser with Web Audio and FLAC decoding; the script does not repair source discontinuities.

02 资源文件 2

03 SKILL.md 正文

Audio Loop

Prepare a source that already joins continuously for Web Audio playback: optionally balance stereo, normalize loudness and encode FLAC. The pipeline does not repair source discontinuities; inspect the join before promising a seamless result.

All ffmpeg work happens in scripts/audio-loop.sh — this skill validates the source, orchestrates the pipeline, and turns the script's summary into a report plus a ready-to-paste JS snippet.

Parameters

Flag Default Description
-t <LUFS> -28 Integrated loudness target (ambient web default)
-v <0..1> 0.6 Target volume baked into the emitted JS snippet
-o <dir> input dir Output directory
-s off Save to ~/.agents/output/{project}/audio-loop/{slug}/
-S off Force no-save
-B off Disable stereo balance auto-correction

Where each flag is handled. -t, -o, and -B pass through to scripts/audio-loop.sh. -v is skill-only — the agent reads it from $ARGUMENTS and interpolates it into the TARGET constant of the emitted JS snippet; the script never sees it. -s / -S follow the repo save-mode convention — the agent translates -s into an -o <save_path> passed to the script, where <save_path> is ~/.agents/output/{project}/audio-loop/{slug}/ ({project} = kebab-cased basename of the git toplevel, else cwd; create it $HOME-expanded, report the fully-expanded absolute path — no tilde, no magic).

Deliberately no crossfade flag. If the source WAV has a real sample-level discontinuity at the loop boundary, that's source editing — outside this skill's scope. If the user is hearing a bump with FLAC + Web Audio, see Diagnostic by negative result below.

Workflow

1. Validate tools

command -v ffmpeg ffprobe. Missing → stop and ask the user to install (macOS: brew install ffmpeg, Debian/Ubuntu: sudo apt install ffmpeg). Never auto-install.

2. Probe the source

The script reads duration, sample rate, channel count, and per-channel RMS via astats. Surface these early — the user sees the starting point before any processing.

3. Diagnose stereo imbalance (stereo sources only)

The script uses 1 dB RMS as its chosen correction threshold, applying a pan filter unless -B is set. Use -B to preserve intentional stereo asymmetry:

pan=stereo|c0=FL|c1=<gain>*FR     # if R is louder
pan=stereo|c0=<gain>*FL|c1=FR     # if L is louder

Where gain = 10^(-|delta_dB| / 20). The script computes delta_dB from the astats pass, picks the right direction, and wires the filter accordingly. At or below the chosen 1 dB threshold no filter is applied. This is a workflow default, not a universal perceptual guarantee.

4. Run the pipeline

$SKILL_DIR = this skill's folder — ${CLAUDE_SKILL_DIR} in Claude Code, the directory containing this SKILL.md elsewhere.

bash "$SKILL_DIR"/scripts/audio-loop.sh <input> [flags]

The script chains: probe → (optional pan correction) → loudnorm=I=<target>:TP=-2:LRA=7 → aresample=<source_rate> → asetnsamples=n=4608:p=0 (bounded frames without padding) → encode FLAC (-c:a flac -compression_level 8). It emits RESULT: key=value lines on stdout.

5. Report

Parse RESULT: lines and compose:

  • Size comparison (source → FLAC, MB)
  • Final integrated loudness + true peak
  • Per-channel RMS confirming the balance is centred
  • A drop-in Web Audio JS snippet tuned to the file's URL and the -v target

Report template:

| File | Size | Codec | Integrated LUFS | True peak |
|------|------|-------|-----------------|-----------|
| `<stem>.flac` | X MB | FLAC | -28.0 | -2.0 dBFS |

Stereo balance: L -19.70 dB / R -19.71 dB — centred (Δ 0.01 dB)
Duration: 6.50 s · Sample rate: 48 kHz · Channels: 2

Web Audio snippet (paste-in-page):

<script>
(() => {
  const AUDIO_URL = '/audio/<stem>.flac'; // adjust to where you serve the file
  const TARGET = <v-value>;
  const FADE_MS = 700;

  let ctx, gain, bufferPromise, entered = false;

  function preload() {
    if (ctx) return;
    const Ctor = window.AudioContext || window.webkitAudioContext;
    if (!Ctor) return;
    ctx = new Ctor();
    gain = ctx.createGain();
    gain.gain.value = 0;
    gain.connect(ctx.destination);
    bufferPromise = fetch(AUDIO_URL)
      .then(r => r.arrayBuffer())
      .then(ab => ctx.decodeAudioData(ab));
  }

  async function unlock() {
    if (entered || !ctx) return;
    try { await ctx.resume(); } catch { return; }
    if (ctx.state !== 'running') return;
    let buf;
    try { buf = await bufferPromise; } catch { return; }
    if (entered) return; // second guard — a concurrent unlock() may have finished during the await
    const src = ctx.createBufferSource();
    src.buffer = buf;
    src.loop = true;
    src.connect(gain);
    src.start(0);
    entered = true;
    const now = ctx.currentTime;
    gain.gain.setValueAtTime(0, now);
    gain.gain.linearRampToValueAtTime(TARGET, now + FADE_MS / 1000);
  }

  const IGNORED = new Set(['Shift','Control','Alt','Meta','Tab','Escape','CapsLock']);
  const onKeydown = e => {
    if (IGNORED.has(e.key)) return;
    document.removeEventListener('keydown', onKeydown, { capture: true });
    unlock();
  };
  preload();
  document.addEventListener('pointerdown', () => unlock(), { capture: true, once: true });
  document.addEventListener('keydown', onKeydown, { capture: true });
})();
</script>

For scroll-tied volume or any multi-channel control surface on top of the baseline, see references/scroll-tied-pattern.md — it documents the multiplicative factors architecture (gain = TARGET × fadeInFactor × scrollVolumeFactor) so additional control dimensions compose cleanly.

Verify the loop boundary

Web Audio loops a decoded buffer; codec decoding and the original signal both matter. FLAC preserves the processed PCM, not the original WAV after normalization or balance changes. decodeAudioData may resample to the AudioContext rate: see MDN.

Inspect decoded endpoints and listen across repeated joins in the target browser before claiming seamless playback. A failed or worsening crossfade does not prove a codec defect: source discontinuity, fade placement, processing and playback can all contribute. Compare lossless source and decoded output to isolate the cause. Report size from actual files rather than predicting a compression ratio.

Diagnostic by negative result

Treat a worse crossfade as evidence against that attempted edit, not a definitive diagnosis. If the source itself does not join, identify the required source edit and continue only within the user's authorized scope. The bundled script has no crossfade operation.

Browser autoplay constraint

Modern browsers block audible playback without a prior user gesture. The emitted snippet attaches one-time pointerdown and filtered keydown listeners on document — any real interaction anywhere on the page unlocks the audio, no splash screen or dedicated button required. mousemove, scroll, and wheel are not gestures per the spec; don't try to hook into them. pointermove isn't either. On reload the unlock must happen again — this is a per-navigation browser constraint with no workaround short of the user granting the origin autoplay privilege explicitly.

Rules

  • NEVER re-encode an already-encoded output — always start from the original WAV (or lossless source). Re-encoding FLAC→FLAC is pointless; re-encoding AAC→FLAC doesn't recover what AAC threw away.
  • Preserve the source sample rate after dynamic loudnorm, which can upsample to 192 kHz. Bound encoder frame size without padding; verify duration/sample count when changing that stage.
  • FLAC is the only encoded output the skill produces. The opinion is deliberate — the "AAC is fine for short loops" habit is the failure mode this skill prevents.
  • Stereo correction uses the chosen Δ > 1 dB default; it does not establish perceptual centering for every source.
  • Default loudness target is -28 LUFS for ambient web audio (quiet-enough-to-not-intrude, loud-enough-to-hear over UI sounds). Louder targets (e.g. -18 for hero music) are a user call — pass -t explicitly.
  • Report source/output sizes and playback verification; retain already-authorized encoding scope.
  • Mono sources skip the balance step (stereo-only concern); everything else (loudnorm, encode) proceeds as normal.
  • When the output path would overwrite the input (FLAC reprocessed in its own directory), the script exits with a clear error — pass -o <dir> to write elsewhere.

04 同仓库更多 Skills

coroboros
coroboros/agent-skills

foo

Fixture skill for repo-kind classifier tests.

★ 5
coroboros
coroboros/agent-skills

foo

Fixture for compound skills + npm tooling detection.

★ 5
coroboros
coroboros/agent-skills

write-clear-readme

Author, restructure, audit or polish a project README for clarity and scannability. Reads repository truth, preserves anchors and code, and verifies rendering. Explicit author/polish requests apply local changes; audit/propose stays read-only. Use for README creation, wording, structure and navigation, including skill collections and CLI/SDK docs.

内容创作者写作与文案Skill与智能体开发
★ 5
coroboros
coroboros/agent-skills

video-loop

Prepare a background video loop for a website with optional crossfade, MP4/WebM encoding and poster extraction. Use for loop joins or web delivery of an existing clip.

图像与多媒体
★ 5
coroboros
coroboros/agent-skills

ultrapex

Adaptive implementation when the user explicitly selects /ultrapex or asks for this adaptive workflow. Establish accepted outcomes, implement, and verify the final result. Generic implementation requests use /apex; use /forge for decisions only and /oneshot for small focused changes.

Skill与智能体开发
★ 5
coroboros
coroboros/agent-skills

suno-produce

Create and revise Suno v5.5 prompt artifacts from a song, track or album brief. Produces TRACK.md, ALBUM.md for explicit multi-track work, and optional ARTIST.md identity. Validates prompt fields and preserves supplied lyrics. Artifact-only; audio generation stays in Suno. Pure lyric writing and audio post-production use other skills.

内容创作者图像与多媒体写作与文案
★ 5