Discover / Video & YouTube
Editly
by mifiTypeScript
Declarative, data-driven video editing from JSON/JavaScript.
Maturity: slowing because no commit in 15 months. Derived from release and commit history, not a rating.
- Stars
- 5.5k
- Forks
- 370
- Downloads / mo
- —
- Last commit
- 2025-05-12
- License
- MIT
- Open issues
- 80
Market and trust evidence
Edition not yet matchedNo exact skills.sh identity match is available for this repository. Repository adoption and freshness remain visible above; install momentum is not inferred.
Trust analysis is a screening signal, not a security warranty. Read the ranking and trust methodology.
In practice
Written by AI from this repository’s README · high confidenceProducing a video programmatically with transitions and overlays normally means chaining fragile ffmpeg invocations.
Use it when
When you want to build a video from a JSON or JSON5 edit spec, or from a JavaScript API, with transitions and music.
Not the right pick when
Needs ffmpeg and ffprobe on PATH, is ESM only, and Linux may require extra headless-gl system dependencies.
Capabilities
- simple CLI plus a more flexible JavaScript API
- streaming editing that is fast and light on storage
- outputs to any dimensions and aspect ratio with automatic letterboxing
- text and subtitle overlays, picture in picture and vignette
- custom HTML5 Canvas or Fabric.js code and custom GL shaders
- automatic audio crossfading, ducking and normalization
Requirements
- Node.js installed
- ffmpeg and ffprobe installed and available in PATH
- Linux may require extra headless-gl system dependencies
- Editly is ESM only
Cost: Free and open source
Install
Derived from the published package name in the repository, not from a model.
Video walkthroughs
Third-party YouTube uploads matched to this tool by title, channel and repository name on 2026-08-03. Not made, reviewed or endorsed by SkillPilot. View counts and publish months are as of the match date and the month is approximate. Nothing loads from YouTube until you press play.
What the repository ships
Detected from the actual files in the repository root.
Latest release v0.15.0-rc.1
Published 2025-01-19
📢 After a couple years of inactivity, editly now has a new maintainer and a new release (candidate).
npm install editly@next
Breaking Changes
- Node 18 is now required.
- Upgrade to Fabric 6 by @bkeepers in https://github.com/mifi/editly/pull/306 - If you are using custom fabric layers, you may need to update your code.
New Features
- Adding fabricImagePostProcessing callback by @Ivanca in https://github.com/mifi/editly/pull/222 and https://github.com/mifi/editly/pull/227
- add right/left parameters - translations by @Kalo0m in https://github.com/mifi/editly/pull/238 and https://github.com/mifi/editly/pull/240
Other Changes
- Rewrite in Typescript by @bkeepers in https://github.com/mifi/editly/pull/307
- Update gl/canvas by @bkeepers in https://github.com/mifi/editly/pull/282
- Bugfix: Ignore video channel when combining arbitrary audio tracks by @bkeepers in https://github.com/mifi/editly/pull/287
- Update Dockerfile by @bkeepers in https://github.com/mifi/editly/pull/312
- Bump various dependencies:
- Bump json5 from 2.2.1 to 2.2.2 by @dependabot in https://github.com/mifi/editly/pull/219
- Bump http-cache-semantics from 4.1.0 to 4.1.1 by @dependabot in https://github.com/mifi/editly/pull/224
- Update miscellaneous deps by @bkeepers in https://github.com/mifi/editly/pull/283
- Bump file-type from 18.7.0 to 20.0.0 by @dependabot in https://github.com/mifi/editly/pull/294
- Chores
- Get GH Actions workflow running on Mac + Linux by @bkeepers in https://github.com/mifi/editly/pull/305
- Run tests against all supported node versions by @bkeepers in https://github.com/mifi/editly/pull/309
- Run examples with GitHub Actions by @bkeepers in https://github.com/mifi/editly/pull/310
New Contributors
- @Ivanca made their first contribution in https://github.com/mifi/editly/pull/222
- @Kalo0m made their first contribution in https://github.com/mifi/editly/pull/238
- @bkeepers made their first contribution in https://github.com/mifi/editly/pull/282
Full Changelog: https://github.com/mifi/editly/compare/v0.14.2...v0.15.0.rc1
Tags
README
image
Discord NPM version Build status PayPal
Editly is a tool and framework for declarative NLE (non-linear video editing) using Node.js and ffmpeg. Editly allows you to easily and programmatically create a video from a set of clips, images, audio and titles, with smooth transitions and music overlaid.
Editly has a simple CLI for quickly assembling a video from a set of clips or images, or you can use its more flexible JavaScript API.
Inspired by ffmpeg-concat, editly is much faster and doesn't require much storage because it uses streaming editing. Editly aims to be very extensible and feature rich with a pluggable interface for adding new dynamic content.
This GIF / YouTube was created with this command: "editly commonFeatures.json5". See more examples here.
Features
- Edit videos with code! 🤓
- Declarative API with fun defaults
- Create colorful videos with random colors generated from aesthetically pleasing palettes and random effects
- Supports any input size, e.g. 4K video and DSLR photos
- Can output to any dimensions and aspect ratio, e.g. _Instagram post_ (1:1), _Instagram story_ (9:16), _YouTube_ (16:9), or any other dimensions you like.
- Content is scaled and letterboxed automatically, even if the input aspect ratio is not the same and the framerate will be converted.
- Speed up / slow down videos automatically to match the
cutFrom/cutTosegment length with each clip'sduration - Overlay text and subtitles on videos, images or backgrounds
- Accepts custom HTML5 Canvas / Fabric.js JavaScript code for custom screens or dynamic overlays
- Render custom GL shaders (for example from shadertoy)
- Can output GIF
- Overlay transparent images or even videos with alpha channel
- Show different sub-clips for parts of a clips duration (B-roll)
- Picture-in-picture
- Vignette
- Preserve/mix multiple audio sources
- Automatic audio crossfading
- Automatic audio ducking and normalization
Use cases
- Create a slideshow from a set of pictures with text overlay
- Create a fast-paced trailer or promo video
- Create a tutorial video with help text
- Create news stories
- Create an animated GIF
- Resize video to any size or framerate and with automatic letterboxing/cropping (e.g. if you need to upload a video somewhere but the site complains
Video must be 1337x1000 30fps) - Create a podcast with multiple mixed tracks
See examples
Requirements
- Windows, MacOS or Linux
- Node.js installed (Use of the latest LTS version is recommended, v12.16.2 or newer on MacOS.)
ffmpeg(andffprobe) installed and available inPATH- (Linux) may require some extra steps. See headless-gl.
- Editly is now ESM only
Installing
npm i -g editly
Usage: Command line video editor
Run editly --help for usage
Create a simple randomized video edit from videos, images and text with an audio track:
editly \
title:'My video' \
clip1.mov \
clip2.mov \
title:'My slideshow' \
img1.jpg \
img2.jpg \
title:'THE END' \
--fast \
--audio-file-path /path/to/music.mp3
Or create an MP4 (or GIF) from a JSON or JSON5 edit spec _(JSON5 is just a more user friendly JSON format)_:
editly my-spec.json5 --fast --keep-source-audio --out output.gif
For examples of how to make a JSON edit spec, see below or examples.
Without --fast, it will default to using the width, height and frame rate from the first input video. All other clips will be converted to these dimensions. You can of course override any or all of these parameters.
- TIP: Use this tool in conjunction with LosslessCut
- TIP: If you need catchy music for your video, have a look at this YouTube or the YouTube audio library. Then use youtube-dl to download the video, and then point
--audio-file-pathat the video file. _Be sure to respect their license!_
JavaScript library
import editly from "editly";
// See editSpec documentation
await editly(editSpec);
Edit spec
Edit specs are JavaScript / JSON objects describing the whole edit operation with the following structure:
{
outPath,
width,
height,
fps,
allowRemoteRequests: false,
defaults: {
duration: 4,
transition: {
duration: 0.5,
name: 'random',
audioOutCurve: 'tri',
audioInCurve: 'tri',
},
layer: {
fontPath,
// ...more layer defaults
},
layerType: {
'fill-color': {
color: '#ff6666',
}
// ...more per-layer-type defaults
},
},
clips: [
{
transition,
duration,
layers: [
{
type,
// ...more layer-specific options
}
// ...more layers
],
}
// ...more clips
],
audioFilePath,
loopAudio: false,
keepSourceAudio: false,
clipsAudioVolume: 1,
outputVolume: 1,
audioTracks: [
{
path,
mixVolume: 1,
cutFrom: 0,
cutTo,
start: 0,
},
// ...more audio tracks
],
audioNorm: {
enable: false,
gaussSize: 5,
maxGain: 30,
}
// Testing options:
enableFfmpegLog: false,
verbose: false,
fast: false,
}
Parameters
| Parameter | CLI equivalent | Description | Default | |
| ----------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | -------------------- |
| outPath | --out | Output path (mp4, mkv), can also be a .gif | | |
| width | --width | Width which all media will be converted to | 640 | |
| height | --height | Height which all media will be converted to | auto based on width and aspect ratio of first video | |
| fps | --fps | FPS which all videos will be converted to | First video FPS or 25 | |
| customOutputArgs | | Specify custom output codec/format arguments for ffmpeg (See example) | auto (h264) | |
| allowRemoteRequests | --allow-remote-requests | Allow remote URLs as paths | false | |
| fast | --fast, -f | Fast mode (low resolution and FPS, useful for getting a quick preview ⏩) | false | |
| defaults.layer.fontPath | --font-path | Set default font to a .ttf | System font | |
| defaults.layer.* | | Set any layer parameter that all layers will inherit | | |
| defaults.duration | --clip-duration | Set default clip duration for clips that don't have an own duration | 4 | sec |
| defaults.transition | | An object { name, duration } describing the default transition. Set to null to disable transitions | | |
| defaults.transition.duration | --transition-duration | Default transition duration | 0.5 | sec |
| defaults.transition.name | --transition-name | Default transition type. See Transition types | random | |
| defaults.transition.audioOutCurve | | Default fade out curve in audio cross fades | tri | |
| defaults.transition.audioInCurve | | Default fade in curve in audio cross fades | tri | |
| clips[] | | List of clip objects that will be played in sequence. Each clip can have one or more layers. | | |
| clips[].duration | | Clip duration. See defaults.duration. If unset, the clip duration will be that of the first video layer. | defaults.duration | |
| clips[].transition | | Specify transition at the end of this clip. See defaults.transition | defaults.transition | |
| clips[].layers[] | | List of layers within the current clip that will be overlaid in their natural order (final layer on top) | | |
| clips[].layers[].type | | Layer type, see below | | |
| clips[].layers[].start | | What time into the clip should this layer start | | sec |
| clips[].layers[].stop | | What time into the clip should this layer stop |
Truncated. Read the full README on GitHub ↗