Frame Sequence Generator
Image frame sequence generator for wordpress. Useful to build seamless scroll animations.
by i-jim666 · github.com/i-jim666/frame-sequence-generator · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/i-jim666/frame-sequence-generator/archive/refs/heads/main.zipReadme
Frame Sequence Generator
A WordPress plugin that turns a Lottie animation, a video, or a ZIP of images into a numbered frame sequence inside the uploads folder, and hands back the two values a scroll-scrubbed canvas block needs: the first frame URL and the frame count.
Scroll sequences are drawn on a canvas from a folder of numbered images. Producing that folder normally means converting the animation by hand and uploading the result over SFTP. This plugin does it from Media → Frame Sequences.
wp-content/uploads/frame-sequences/my-animation/
├── frame-000.webp
├── frame-001.webp
├── …
└── sequence.json ← what it was made from
Frames are numbered from zero (frame-000, frame-001, …), zero-padded to at least
three digits — the pattern the front end walks.
Requirements
| WordPress | 5.6+ |
| PHP | 7.0+ |
| Capability | upload_files (editors and up) |
| ZIP input | PHP zip extension |
| Video / animated GIF input | ffmpeg on the server (optional) |
| Resizing / format conversion | GD or Imagick (optional) |
Nothing beyond WordPress itself is required for the main path — Lottie files with embedded frames are copied out byte-for-byte using plain PHP.
Installation
cd wp-content/plugins
git clone git@github.com:i-jim666/frame-sequence-generator.git
Activate Frame Sequence Generator in Plugins, then open Media → Frame Sequences.
Usage
- Drop a file onto the upload area.
- The file is analysed and sensible defaults are proposed (aiming for ~120 frames).
- Adjust the name, frame count, format and maximum width if needed, and generate.
- Copy the first frame URL and frame count into the block's Frame sequence fields.
Supported input
| Input | Extensions | Notes |
|---|---|---|
| Lottie / Bodymovin | .json, .lottie |
Embedded raster frames are copied out with no re-compression. Playback order comes from the layer list, not asset order. |
| Image sequence | .zip |
Numbered PNG/JPEG/WebP, sorted the way a human counts (frame2 before frame10). |
| Video / animated | .mp4 .m4v .mov .webm .mkv .gif .webp .apng |
Requires ffmpeg. |
A .zip is inspected on arrival: if it contains an animation JSON it is treated as a
dotLottie archive, otherwise as a folder of images.
A genuine vector Lottie has no frames to extract and PHP cannot rasterise it. The plugin detects this and says so, rather than failing obscurely — export an image sequence or an MP4 from After Effects and upload that instead.
Options
- Frames to keep — source frames are sampled at a fixed step. The default targets about 120 frames, which scrubs smoothly without a punishing download.
- Format — only formats this server can actually write are offered. Keep original never re-compresses and is always available.
- Maximum width — scales frames down when the source is larger than needed.
Managing sequences
Every generated sequence is listed under Your sequences with a Delete button. Before
deleting, the plugin searches post_content and postmeta for pages still referencing
that folder and warns you by name.
Scan uploads folder finds sequences placed by hand before the plugin was installed, so those can be copied or removed here too.
How it works
Streaming Lottie parsing
A 480-frame Lottie export runs to tens of megabytes; json_decode()ing it whole would
exhaust a shared host's memory limit. Instead the file is read in a windowed pass that
records the byte offset and length of each base64 payload, while everything between the
payloads is stitched into a small "skeleton" — the same JSON with each blob replaced by a
marker — which is cheap to parse and yields the real playback order from the layer list.
A 52 MB animation uses roughly 2 MB of memory this way, against 100 MB+ for a full decode.
Frame format is sniffed from the bytes rather than trusted from the declared MIME type;
these exports routinely label WebP payloads as image/png.
Batched writes
Frames are written in small batches with a 12-second wall-clock guard per request, so a 500-frame sequence never depends on one long request surviving the host's timeout. The browser drives the loop and shows progress. Passthrough copies run 40 frames per batch; re-encoding runs 8. Video extraction is the exception: ffmpeg writes the frames itself in one background process that the UI polls.
Jobs
Uploads live in uploads/frame-sequences/.jobs/<id>/, protected by .htaccess and an
index.php. A job belongs to the user who started it, and a daily cron sweep
(fsg_cleanup_jobs) discards anything older than 24 hours that was never finished.
Deletion safety
- Paths from the client are resolved against the uploads root and re-checked there — never trusted as given.
- Deletion refuses anything outside
wp-content/uploads, and refuses the uploads root. - Only the frames
describe()actually identified are removed. Anything else in the folder survives and is reported back. - Outside the plugin's own folder, a directory must look like a sequence — at least 8
frames, an unbroken run of numbers, and ≥80% of the folder's images belonging to that
run — before it can be touched at all.
uploads/2026/08fails that decisively.
Layout
frame-sequence-generator.php Bootstrap: constants, requires, cron wiring
includes/
class-fsg-env.php What this server can do (GD, Imagick, ffmpeg, zip)
class-fsg-library.php Sequence discovery, description, usage search, deletion
class-fsg-job.php Job lifecycle and the per-frame index
class-fsg-image.php Sniffing, dimensions, resize/convert
class-fsg-source-lottie.php Streaming Lottie/dotLottie parser
class-fsg-source-files.php ZIP extraction and natural-sorted image lists
class-fsg-source-video.php ffmpeg probe and extraction
class-fsg-ajax.php Endpoints
class-fsg-admin.php Media → Frame Sequences screen
assets/
admin.css
admin.js
AJAX endpoints
All are admin-ajax.php actions prefixed fsg_, guarded by the upload_files
capability and an fsg nonce.
| Action | Purpose |
|---|---|
fsg_upload |
Receive and analyse a source file, create a job |
fsg_start |
Apply options, prepare the output folder |
fsg_batch |
Write the next batch of frames |
fsg_progress |
Poll ffmpeg extraction |
fsg_finish |
Write sequence.json, destroy the job |
fsg_cancel |
Discard a job |
fsg_list |
List sequences (optionally scanning uploads) |
fsg_usage |
Find content referencing a sequence |
fsg_delete |
Delete a sequence |
fsg_redetect |
Re-probe for ffmpeg |
Configuration
Constants, all optional, definable in wp-config.php before the plugin loads:
// Folder inside wp-content/uploads that holds every sequence.
define( 'FSG_FOLDER', 'frame-sequences' );
// Capability required to generate and delete sequences.
define( 'FSG_CAP', 'upload_files' );
// Skip ffmpeg auto-detection and use this binary.
define( 'FSG_FFMPEG_BIN', '/usr/local/bin/ffmpeg' );
Troubleshooting
ffmpeg is installed but not detected. The web server's PATH is usually narrower
than a login shell's. The plugin probes ffmpeg, /usr/bin, /usr/local/bin,
/opt/homebrew/bin, /opt/local/bin and /snap/bin, and caches the answer for a day.
Use Check again for ffmpeg under What this server can do, or set FSG_FFMPEG_BIN.
"That file is larger than this server accepts." The upload never reached PHP. Raise
upload_max_filesize and post_max_size, or upload a smaller export.
The sequences folder is locked. wp-content/uploads/frame-sequences must be
writable by the web server user.
No WebP option. This server has no WebP encoder. Frames that are already WebP still come through untouched via Keep original.
License
GPL-2.0-or-later.