Loppiner Loop Extractor
Got a video that repeats? This node cuts out exactly one loop cycle
- images
- images
- period_frames
- start_frame
- confidence
- estimated_loops
- status
Looping is a whole genre in local video generation - AnimateDiff made seamless loops one of its few surviving selling points, Hunyuan's 201-frame "natural loop" is really just the model repeating a frame, and the VACE Video Joiner added a Make Loop toggle in 2026. That's the generation side. The Loppiner Loop Extractor works the other way: you hand it a batch of frames that already contains repeated cycles, and it finds one clean cycle and hands it back. Think turntable renders, character animation that cycled a few times, a generated clip you let run long. Instead of eyeballing frame numbers, this node does the math.
It's a slicing utility, not a model - no checkpoints, no downloads, no API, no key. Just torch, which ComfyUI already ships. That's rare and nice.
How it works
The clever part is that it never looks at full-resolution pixels. Each frame gets shrunk to a tiny grayscale thumbnail (16×16 in fast, 32×32 in pro/strict), normalized, and flattened into a feature vector. pro mode adds a DCT of the thumbnail plus edge energy, and it binarizes the DCT coefficients into "bits" for a cheap perceptual hash. Then it does what's essentially lag autocorrelation: for every candidate period between min_period_frames and max_period_frames, it compares frame i with frame i+lag and averages the difference. The lag with the lowest difference wins.
From there it does the work that makes it usable:
- Fundamental period de-harming - if 12 frames look periodic, it checks whether 6 or 4 also work (divisors) and prefers the shorter period, so you get the actual cycle, not a multiple of it.
- Phase search - finds the best start frame so the cycle begins at a sensible point, not mid-motion.
- Confidence - how much better the winning period is than the noise baseline.
confidence_thresholdof 0 uses per-mode auto values (fast 0.34, pro 0.44, strict 0.56).
strict mode adds the one thing the others skip: a seam check. It measures the distance from the last frame of the cycle back to the first, and compares it against the average distance between adjacent frames inside the cycle. If the seam is worse than about 1.18× the mean adjacent distance, the loop is rejected - that's the "ping-pong" and visible-jump detection you'd otherwise discover after exporting.
Inputs that matter
You really only touch a few of these:
- images - a standard
IMAGEbatch,[frames, height, width, channels]with 1, 3, or 4 channels. Feed it straight from a video loader or a VAE-decoded batch. Needs at least 8 frames; anything shorter just passes through. - mode -
fast(cheap, 16px features),pro(default, more robust),strict(pro + seam validation). - fallback_strategy -
originalreturns your whole batch untouched if no confident loop is found;best_effortreturns the closest cycle candidate anyway.originalis the sane default for most work. - max_period_frames - 0 means automatic, which caps at half the batch length. That's deliberate: you need at least two full cycles to detect one.
The five remaining outputs are the debugging story: period_frames, start_frame, confidence, estimated_loops, and status, a text string that tells you exactly what happened (LOOP_FOUND, NO_LOOP_DETECTED_RETURNED_ORIGINAL, STRICT_SEAM_FAIL_...). Wire images forward and drop status into a text preview while you dial in the mode - it's the whole interface for figuring out why a loop got rejected.
Install
The README says copy the folder into ComfyUI/custom_nodes/ and restart, which works, but the usual route is cleaner:
cd ComfyUI/custom_nodes
git clone https://github.com/adbrasi/loppiner
Restart ComfyUI and search for "Loppiner Loop Extractor". ComfyUI Manager can find it as loppiner. There's no requirements.txt - the only dependency is torch, which ComfyUI already has, so no install step and no environment risk. One thing worth knowing: this is a brand-new, single-maintainer pack with essentially zero community footprint, so there's no thread to search when something's off - read the status string, it says more than any error log.
Common issues
- You get the original batch back with no slicing. Check
status. Either the batch was under 8 frames (NO_LOOP_TOO_SHORT_RETURNED_ORIGINAL) or nothing periodic was found (NO_LOOP_DETECTED_RETURNED_ORIGINAL). If your footage genuinely loops but detection misses, gopro(orstrict) and lowerconfidence_thresholda notch. strictreturns original on stuff that looks like it loops. That's the seam check doing its job - the last→first jump was too big, so the loop would've visibly stuttered. That'sSTRICT_SEAM_FAIL_RETURNED_ORIGINAL. Switch toproif you want the cycle anyway.- It's slow on huge batches. The lag scan is O(periods × samples) per frame set. Long 4K batches are where
fastmode earns its keep, and you can capmax_period_framesinstead of letting it scan to half the batch.
The one workflow shape to remember: generate long, extract the cycle, then feed that short clean loop back into anything - an upscaler, a video joiner, a GIF exporter. The node hands you the minimal repeating unit; everything after that gets dramatically easier.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| mode | COMBO | pro | 3 options: fast, pro, strict |
| fallback_strategy | COMBO | original | 2 options: original, best_effort |
| min_period_frames | INT | 62–100000 | — |
| max_period_frames | INT | 00–100000 | — |
| confidence_threshold | FLOAT | 0.000–1 | — |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| period_frames | INT | — |
| start_frame | INT | — |
| confidence | FLOAT | — |
| estimated_loops | FLOAT | — |
| status | STRING | — |