---
name: engine-fux
description: One-shot MIDI chord-loop scraper. User names a song, artist, or album — skill auto-creates a folder on their Desktop named after the target, scrapes real chord MIDIs from the wild (Online Sequencer for human transcriptions, then YouTube instrumentals → audio chord detection as fallback), auto-extracts to N-bar CHORD LOOPS ONLY (no drums, no melody leads, no full-song MIDIs in the final folder), and drops them ready for FL Studio. TRIGGER on ANY of these patterns (even if user doesn't say "scrape" or "engine-fux" explicitly) - "get me [X] midis", "scrape [X]", "pull every [artist] chord loop", "grab the whole [album]", "find midis for [song]", "download [X] chords", "[album/song/artist] midis please", "rip [X] midis", "any [artist] chord midis". Defaults - 8-bar loops, chord-only output, folder named after the target. Use this BEFORE midi-cook — only fall back to midi-cook if the user explicitly wants original/generated content, not transcriptions of real songs.
---


# engine-fux

One-shot: user names a target, skill delivers a clean Desktop folder of chord-loop MIDIs.

## The flow (follow exactly, no clarifying questions unless target is unintelligible)

```
USER: "scrape Luv Is Rage 2"
SKILL: → ~/Desktop/Luv Is Rage 2/
       → Track 1 [8bar chords].mid
       → Track 2 [8bar chords].mid
       → ... (chord loops only)
       → reports: "got 17/17, 3 from OS / 14 from audio detection"
```

**1. Parse target.** Extract from prompt: song name, artist name, OR album name. If album, look up the full tracklist. Pick a folder name that matches the user's phrasing — e.g. "Luv Is Rage 2", "pierre midis", "carti die lit".

**2. Create folder.** `mkdir -p ~/Desktop/<target>/`. Nothing else on disk — no tmp folders in Desktop, no `_full songs/` subfolder, no raw MIDI dumps the user has to look at. Staging happens under `/tmp/`.

**3. Pipeline A — Online Sequencer scrape** (always try first, output is highest quality):

  a. WebSearch `site:onlinesequencer.net "<song name>"` (or `site:onlinesequencer.net "<artist>"` for broader sweep). For albums, hit 3-5 key track names. Collect seed sequence IDs.

  b. Playwright `browser_navigate` to ONE seed page (e.g. `https://onlinesequencer.net/<id>`). Must be an actual sequence page — the audio context needs to initialize or `song.setBPM` throws.

  c. `browser_evaluate` running the JS from `scripts/os_bfs_export.js` with `seedIds` + `titleRegexSrc` (e.g. `"uzi|xo\\s*tour|sauce it up"`). It BFS-walks inspired chains + uploader profiles, hooks `saveBlob`, exports each matching sequence, returns `{midis: {id: {title, b64, size}}}` as a JSON file.

  d. Run `scripts/extract_chord_loops.py <json> <target folder> --bars <N>` — decodes base64, scores tracks by polyphony+register+note-length, picks the chord track of each MIDI, extracts first N bars, dedupes by MD5. Output name format: `<Song Title> [<N>bar chords].mid`.

**4. Pipeline B — Audio → chord triads** (fallback for missing targets):

  a. Figure out which target tracks Pipeline A didn't cover. For each missing one:
     ```bash
     yt-dlp --default-search ytsearch1 -x --audio-format mp3 \
       --postprocessor-args "ffmpeg:-ss 30 -t 45" \
       -o "<safe-title>.%(ext)s" \
       "ytsearch1:<artist> <song> instrumental"
     ```
  Parallelize with `&` + `wait` — 10+ tracks in ~30-60 seconds.

  b. `bash scripts/setup_env.sh` if venv doesn't exist (idempotent, ~90s first time, instant after).

  c. `/tmp/bp_env/bin/python scripts/audio_to_chord_midi.py <audio dir> <target folder> --bars <N>`
     librosa HPSS + chroma_cqt + beat-track + 24-chord template match → root-3rd-5th triad MIDIs at detected BPM. Filename: `<Song> [<bpm>bpm] (<chord progression>) <N>bar.mid`.

**5. Clean up.** Delete any `/tmp/` staging. Dedupe folder by MD5. Drop files under 150 bytes (sparse/junk). For songs with multiple OS transcriptions, keep just the biggest/richest unless user said "all versions".

**6. Report honest status** — X tracks, Y from OS (real transcriptions), Z from audio detection. If bulk came from audio detection, warn: "the audio-detected ones only output root-3rd-5th triads, not 7ths/extensions — treat them as starting sketches, not final chords."

## Default parameters (use unless user overrides)

- **Bars:** 8. User may say "4 bar", "16 bar" etc — honor it.
- **Folder location:** `~/Desktop/`. Only change if user specifies a different path.
- **Folder name:** Derive from user's phrasing. "luv is rage 2" → `Luv Is Rage 2/`. "carti midis" → `carti midis/`. Match their casing/tone.
- **Output format:** Chord MIDIs only. No drums, no full songs, no melody leads. That's the whole point.
- **Dedupe:** On by default. Different transcriptions of the same song → keep just the best one.

## Tools you'll need

- `WebSearch` (for Google site:onlinesequencer.net dorks)
- `mcp__plugin_playwright_playwright__browser_navigate` + `browser_evaluate` (Pipeline A)
- `Bash` + `yt-dlp` + `ffmpeg` (Pipeline B audio download)
- `/tmp/bp_env/bin/python` (venv from setup_env.sh, Pipeline B extraction)

## Setup (only needed once per machine)

```bash
bash "$SKILL_DIR/scripts/setup_env.sh"
```

Idempotent. Creates `/tmp/bp_env/` with librosa + basic-pitch + mido + pretty-midi. Patches the scipy.signal.gaussian deprecation in basic-pitch. After this, all future runs are instant.

## Why two pipelines

Pipeline A (Online Sequencer) is gold — a human played the notes in. But OS coverage is sparse: classics like "XO Tour Llif3" have 8 variants, deep cuts have zero.

Pipeline B (audio detection) fills the gap but has hard limits worth knowing:
- Detects major/minor triads only — no 7ths, sus, extensions
- BPM detection flips between half/double time on trap beats (~30% wrong)
- No key constraint — occasional out-of-key chord detections
- Fixed C4 voicing, not the song's real voicing

Use A first. Fall back to B only for what A missed. If the user needs actual chord quality for a B-heavy result, note it honestly and offer the Demucs + key-constrained upgrade path (not implemented yet).

## Key gotchas (save yourself 20 minutes of debugging)

- The OS saveBlob hijack only works ON an actual sequence page. Navigating to `/sequences?search=...` doesn't init the audio context → `song.setBPM` throws.
- `loadDataProto` accepts binary Uint8Array; decode the base64 string from the page first to avoid lib-version footguns.
- After loadDataProto, global `bpm` is stale. Sync with `song.setBPM(parseFloat(document.getElementById('bpm').value))` or exportMidi writes at wrong tempo.
- Some OS exports are stubs with no chord content (pure drums or 2-note melodies) — extract_chord_loops.py filters these via score <= 0.
- For Pipeline B, always `-ss 30` into the track — intros skip the chord progression.
- Half-tempo BPM: normalize loop `while bpm < 120: bpm *= 2; while bpm > 200: bpm /= 2` is a heuristic. Tell user to retempo in FL if the beat feels off.
