Skip to content

Releases: Y0lan/dj-edit

v0.3.0 — content-aware Insta360 + GUI launcher + codex round-1 fixes

Choose a tag to compare

@Y0lan Y0lan released this 13 May 08:55

Content-aware Insta360 reveals + GUI wrapper. v0.2 hardcoded yaw targets,
so reveals had a coin-flip chance of pointing at the DJ booth versus a wall.
v0.3 scores Insta360 ERP footage frame-by-frame for motion + brightness and
points camera moves at the actual content.

Added

  • bin/score-360.py — content-aware Insta360 yaw scoring. Samples
    source frames at 1 fps in grayscale, slices into 8 horizontal yaw segments
    (45° each), and emits per-segment motion + brightness scores to
    sphere_score.json. Single-pipe ffmpeg → numpy, near-constant memory.
  • lib/sphere.py:best_yaw_at — pure helper that queries sphere_score
    at a given source-local time and returns the yaw with highest weighted
    motion + brightness. Returns None on all-zero windows so callers fall
    back to move defaults. ERP-circular smoothing pools seam-adjacent
    segments so subjects straddling 337.5/22.5° aren't dropped.
  • start_yaw parameter on orbit, crowd_reveal, bpm_sync_orbit,
    breakdown_drift
    — content-aware anchoring. Default start_yaw=0
    preserves v0.2 behavior byte-identically.
  • start_yaw + shortest-path delta on drop_impact — a target yaw of
    337.5° now whips -22.5° (the short way) instead of spinning 337.5°.
  • Enhanced dj-edit-mac.command with launch menu (New / Re-edit recent /
    Quick test / Demo / Doctor), style picker (signature / aggressive / clean),
    reference picker (anyma / fisher / rinse), and a "quick test" mode that
    renders only the highest-intensity drop (~3 min) before committing to a
    full 30-50 min render. Recent projects saved at ~/.dj-edit-recent.
  • dj-edit score-360 subcommand (placeholder shipped in v0.2.1, now backed
    by real implementation).

Fixed — codex round 1 (HIGH severity)

  • build-edl.py was querying sphere_score with master-timeline time but
    frames are source-local.
    Multi-Insta360 setups also always read
    source_index=0. Now passes source_t=src_in and
    source_path=finfo["path"] so each clip resolves to its own source at the
    right time.
  • drop_impact whipped the long way around when target_yaw > 180°.
    Now computes a signed shortest-path delta in [-180, 180] and animates
    start_yaw + delta * progress.

Fixed — codex round 1 (MEDIUM severity)

  • score-360.py stderr=PIPE could deadlock on long sources where ffmpeg
    emits decode warnings faster than Python reads stdout. Switched to
    DEVNULL and added -nostdin -hide_banner -nostats.
  • sphere.best_yaw_at returned arbitrary yaw=22.5° on all-zero/black
    windows.
    Now returns None and the caller falls back to the move's
    default yaw.
  • score-360.py now emits source_path (project-relative) alongside
    basename, so multi-source matching in build-edl.py works.

Upgrade

brew upgrade dj-edit

v0.2.1 — auto-open output folder after run + deliver — friend was lost without it

Choose a tag to compare

@Y0lan Y0lan released this 13 May 08:32

Third friend-feedback patch. He ran dj-edit run on his real footage and
texted "can't find where the final video is."

Fixed

  • dj-edit run and dj-edit deliver now auto-open the output folder
    when done.
    Previously only dj-edit quickstart did this. Both
    commands now print the location + open out/ on macOS (and xdg-open
    on Linux only when a display is attached, to avoid hanging headless).
  • dj-edit score-360 subcommand placeholder — v0.3+ will ship a real
    implementation (content-aware Insta360 yaw scoring). v0.2.1 dispatcher
    handles "script not yet installed" gracefully so the run chain can
    evolve in v0.3 without breaking v0.2.x users.

Upgrade

brew upgrade dj-edit

v0.2.0 — Tier A eased moves + Tier B music-driven moves + Tier D move pools (with codex-loop hardening)

Choose a tag to compare

@Y0lan Y0lan released this 12 May 12:56

The Insta360 movement upgrade. v0.1.x reframed via static stock moves (orbit at
constant speed, dolly-zoom linear); v0.2 makes camera motion cinematic and
music-aware.

Added — Tier A: eased motion primitives

Every move (orbit, tilt_reveal, dolly_zoom, crowd_reveal) now uses
cosine ease-in-out instead of linear ramps. Two new combined-motion primitives:

  • counter_motion: yaw turns one direction while pitch oscillates and h_fov
    breathes. Three orthogonal motions from one cheap source.
  • dolly_with_drift: push-in plus slow yaw drift. Subject-lock effect.

Added — Tier B: music-driven moves

  • bpm_sync_orbit: yaw rotates exactly N bars per full turn, BPM-locked.
  • kick_pulse_fov: h_fov pumps at BPM frequency for subliminal beat sync.
  • drop_impact: 4-phase preset (freeze → whip → dolly-zoom → hold) for
    the moment of impact.
  • build_tension: quadratic-ease h_fov tightening into the drop.
  • breakdown_drift: ultra-slow yaw + slow pitch tilt for breakdowns.

Added — Tier D: stochastic move pools

  • lib/selector.pick_move_for_event: weighted RNG pick, intensity-biased,
    with 3-pick avoid-repeat window. Same set rendered twice → different cuts.
  • presets/styles/{aggressive,clean,signature}.json: weight overrides.
    aggressive ships drop_impact every drop + whip-pans dominating; clean is
    cinematic and slow; signature is the balanced default.
  • presets/references/{anyma,fisher,rinse}.json: artist-style packs.
  • --style, --reference, --seed CLI flags on dj-edit edl.

Fixed — codex round 1 + 2 (CRITICAL)

  • TI is normalized [0,1] in sendcmd, NOT seconds. Rewrote every move's
    math to use T (absolute seconds) instead of bare TI. The v0.1 expressions
    like 45*TI meant "45 degrees TOTAL" — not "45 deg/sec" as designed.
  • Commas inside sendcmd expressions break parsing (verified in ffmpeg
    n8.1.1). Replaced piecewise if(lt(x,a),b,c) with multi-line time-windowed
    commands (each command on its own line, no nested if). Replaced pow(T,2)
    with T*T.
  • Render cache only hashed EDL JSON, not cmd file contents. Tweaking a
    move generator while EDL JSON stayed byte-identical → cache served stale
    video. Now hashes EDL plus every referenced .cmd file's content.
  • _generate_move_cmd returned a relative cmd path. Broke when render.sh
    was invoked from a different cwd. Now returns .resolve() absolute path.
  • target_yaw or 60.0 made explicit target_yaw=0.0 impossible. Now uses
    target_yaw is None check.
  • load_pool_overrides silently fell back to defaults on --style typo.
    Now warns to stderr (with the resolved file path) for missing pack files,
    malformed JSON, or pack entries referencing unknown move names.
  • Intensity not clamped. Negative or >1 event intensities could produce
    zero or negative weights in pool selection. Clamped to [0, 1].

Added — Tests + CI hardening

  • 131 pytest tests (up from 41 in v0.1.x). Includes:
    • 21 lib/moves invariant tests (no-pow, no-if, no-commas, uses-T)
    • 14 selector pool-selection tests (weight bias, avoid-repeat, packs load)
    • 60 shipped-preset hygiene tests (12 presets × 5 invariants) — this
      test set automatically catches the codex round 1 regression class (where
      presets weren't regenerated after a lib rewrite).
  • Full quickstart --demo end-to-end smoke verified: drop detected, set_9x16
    • set_16x9 + highlight + per-drop clip all produced in ~8 seconds.

Verified end-to-end

All 12 generated .cmd files render through real ffmpeg n8.1.1 sendcmd (orbit,
drop-impact, build-tension, kick-pulse-fov tested with rgbtestsrc input;
frames at t=0 and t=1s have different md5sums → motion confirmed).

Upgrade

brew upgrade dj-edit

v0.1.3 — fix quickstart --demo: bake audio into demo video + sharpen drop transient

Choose a tag to compare

@Y0lan Y0lan released this 12 May 11:52

Second friend-feedback patch. dj-edit quickstart --demo now actually completes
end-to-end with a detected drop and a rendered per-drop clip.

Fixed

  • demo_video.mp4 had no audio track. dj-edit sync requires camera scratch
    audio to cross-correlate against the master — without it, no offsets, empty
    EDL, zero clips. Fix: bake the demo audio INTO the demo video so sync resolves
    trivially.
  • Synthesized drop didn't trigger detection. The previous demo "drop" at
    t=15s was a slow volume ramp, which librosa's onset_strength saw as nothing
    remarkable. Fix: regenerate demo_audio.wav with a sharp sub-bass impact at
    t=15s plus a noise impulse for the onset trigger. Analyze now finds:
    build @ 7s + drop @ 15s (intensity 1.0).

Result

dj-edit quickstart --demo now produces in 8.6s:

  • set_9x16.mp4 + set_16x9.mp4 (full 30s timeline)
  • highlight_9x16.mp4 (drop reel)
  • drops/drop_01_t00m15s_int100.mp4 (timestamp + intensity in filename)
  • drops/INDEX.txt (tracklist)

A proper smoke test of the install.

Upgrade

brew upgrade dj-edit

v0.1.2 — fix doctor false-positive + brew formula /Applications crash

Choose a tag to compare

@Y0lan Y0lan released this 12 May 11:45

First friend-feedback patch. Two real bugs hit on macOS install.

Fixed

  • Brew install crash on /Applications. The formula tried to write
    dj-edit-mac.command directly to /Applications via Ruby's File.write,
    which fails inside brew's install sandbox. Friend had to manually patch
    the formula to skip that step. Fix: install the .command into share/
    only; caveats instruct the user to copy it to /Applications themselves
    (one extra cp line, but no install crash).
  • Doctor false-positive on filter detection. Friend's dj-edit doctor
    reported loudnorm (and earlier drawtext) as missing even though
    ffmpeg -filters | grep loudnorm showed them present. Root cause: the
    regex ^ ?[.TS]+ +<name> + was sensitive to ffmpeg's leading-whitespace
    pattern, which varies across versions/builds. Fix: parse column 2
    directly with awk ($2 == filter_name). Same fix on the encoder check.

Upgrade for existing users

brew upgrade dj-edit

v0.1.1 — render cache + 41 pytest unit tests + CI matrix

Choose a tag to compare

@Y0lan Y0lan released this 12 May 11:41

Quality + resilience pass. No new user-facing features; faster re-runs and confidence in correctness.

Added

  • Output-level render cache in bin/render.sh. Keyed on sha256(canonical_edl_json).
    Re-runs with the same EDL skip the encode entirely and copy from cache (<1s vs 25-40 min).
  • 41 pytest unit tests across lib/treatments, lib/selector, lib/moves, and
    bin/sync-cameras.robust_offset. Catches regressions in pure logic without needing
    real video fixtures.
  • GitHub Actions CI: matrix on ubuntu-latest + macos-latest × Python 3.11/3.12.
    Runs pytest, bash/python syntax checks, and dj-edit quickstart --demo smoke test.
  • scripts/release.sh one-command release helper. Bumps version, tags, creates
    GitHub release, computes tarball SHA256, updates the brew formula in the tap.

Fixed

  • robust_offset in bin/sync-cameras.py now takes optional cam_dur to filter out
    clipping-at-master-end artifacts more aggressively. Caught by test_sync_helpers.py.
  • Attempted a per-chunk render cache approach for mid-render resume, but reverted due to
    3-5x slowdown vs monolithic (per-chunk decode setup on a 64GB source doesn't share work).
    Output-level cache is the cleaner solution for the common iteration case.

Notes

  • v0.2 will add: per-camera LUTs (color match), Songrec track-ID burn-in, --style
    knob that actually changes pacing, watermark + endcard. See lexical-percolating-bee.md
    in the plan archive for full backlog.

v0.1.0 — Initial public release

Choose a tag to compare

@Y0lan Y0lan released this 12 May 11:08

First public release of dj-edit.

Auto-edit DJ-set videos with audio-driven cuts. Detects drops, builds, breakdowns from a master audio recording and produces 9:16 + 16:9 outputs with beat-snapped cuts, virtual-camera reframing, and drop-impact treatments.

What works in v0.1.0

  • Single-camera Sony A7-III + Tascam recorder workflow (tested on real 90+ min sets)
  • Multi-feature audio analysis (librosa onset + band RMS + spectral centroid + beat_track at 128 BPM hint)
  • Affine camera sync via onset-envelope cross-correlation with median-offset estimator
  • Multi-aspect render (9:16 + 16:9) via one ffmpeg filter_complex graph
  • Platform auto-detect encoder: videotoolbox (macOS) / vaapi (Linux) / libx264 (fallback)
  • Per-drop clip extraction with timestamp + intensity in filename
  • Top-6 drops highlight reel
  • macOS GUI launcher (dj-edit-mac.command via osascript folder pickers)
  • dj-edit doctor health check
  • dj-edit quickstart --demo smoke test with bundled 30s synthesized fixture

Install (macOS)

```bash
brew tap Y0lan/dj-edit
brew install dj-edit
```

Then double-click `/Applications/dj-edit-mac.command` or run `dj-edit help`.

Install (Linux / from source)

```bash
git clone https://github.com/Y0lan/dj-edit.git
cd dj-edit
./setup.sh
```

Status

This is an alpha release. Multi-camera (Insta360 + DJI) path exists but is undertested. Pre-built Homebrew bottles will land in v0.1.1 once CI infra is set up — for now the brew formula builds from source (~3 min extra install time).

Built with Claude Code (Claude Opus 4.7).