Skip to content
CutConvert

CutConvert Edit JSON, version 1

CutConvert Edit JSON, version 1: every field, rule and pattern of the document that becomes a CapCut, Premiere Pro, DaVinci Resolve or Final Cut Pro project.

Updated

One JSON document describes one edit: the media it uses, the clips on each track, captions, titles, cross dissolves and markers. CutConvert turns it into a project that opens in CapCut, Premiere Pro, DaVinci Resolve or Final Cut Pro, with captions and titles as text you can edit there.

The JSON Schema is schema.json. A test keeps this page, that schema and the validator in step: every field below is in both, with the type, whether it is required and the rules given here, and nothing else is.

Rules that hold everywhere

  • Times are seconds, as decimals, from 0 to 1,000,000, and no clip ends later. Each time is moved to the nearest frame of the timeline, half a frame at most. A clip's out point follows from its in point and its length in frames, so it carries both their roundings. A file ends with its last whole frame: a file with a picture, with its own last frame at its own rate, even when its duration runs on with its sound. When a clip would run past that end, its in point moves back, and when the in point is already at 0, the clip ends early by whole frames, leaving a gap before the next. That happens to a clip used to the end of its file above 100%, where each frame of the clip takes several of the file's, and also at 100% when the file's rate isn't the timeline's (2 s of a 25 fps file on a 29.97 timeline is 59.94 frames, and the clip ends on frame 59). A clip with a start, end, in or out point that moves by more than half a frame, or that ends early, gets one edit-time-snapped warning saying what moved and why. Anything that would last less than a frame is an error, dissolves and fades included.
  • Positions are fractions of the frame, from −10 to 10. 0.5, 0.5 is the centre, x runs right and y runs down. A clip's position is where the centre of its picture lands.
  • Font sizes and stroke widths are pixels on the timeline's canvas.
  • Volume is in dB. 0 leaves a clip as it is. −96 or lower is silent.
  • Names, paths and fonts are one line. Caption and title text may hold line breaks (\n) and tabs. No other control character is allowed anywhere, U+007F to U+009F included.
  • Lengths count characters, as JSON Schema does: an emoji is one character, though it takes two UTF-16 units.
  • Unknown fields are errors. A misspelt field fails validation rather than being ignored.
  • A document places up to 20,000 clips, captions and titles in all, a video clip whose file has sound counting twice, for its sound.
  • A document that fails validation fails with every problem listed, each with its path, such as video[0].clips[2].out: must be after in (6 s). One error lists the first 50, then how many more. Anything of yours a message or an edit- warning repeats, such as an unknown field, a media id, a file name or a track name, is quoted as JSON and cut to about 60 characters, with invisible characters (U+0085, bidi controls, zero-width spaces) written as \uXXXX. The editors' own warnings repeat your names as they are, with invisible characters written the same way.
  • Version 1 only grows. Later versions add optional fields. No field is renamed or removed, and a version 1 document stays valid.

The document

{
  "cutconvert": "edit/1",
  "name": "Episode 41 clip 3",
  "timeline": { "fps": 29.97, "width": 1080, "height": 1920, "startTimecode": "00:00:00:00" },
  "media": [
    { "id": "src", "name": "episode-41.mp4", "path": "/Users/sam/Movies/episode-41.mp4",
      "duration": 3612.4, "fps": 29.97, "width": 1920, "height": 1080,
      "audio": { "streams": [2], "sampleRate": 48000 } },
    { "id": "bed", "name": "bed.mp3", "duration": 184.0, "audio": { "streams": [2], "sampleRate": 44100 } }
  ],
  "video": [
    { "name": "V1", "clips": [
      { "media": "src", "start": 0, "in": 812.4, "out": 847.1,
        "position": { "x": 0.5, "y": 0.5, "keyframes": [ { "t": 0, "x": 0.44, "y": 0.5 }, { "t": 12.5, "x": 0.56, "y": 0.5 } ] },
        "scale": 178, "volume": 0 },
      { "media": "src", "start": 34.7, "in": 1201.0, "out": 1211.0, "scale": 178 }
    ] }
  ],
  "audio": [
    { "name": "A2", "clips": [ { "media": "bed", "start": 0, "in": 0, "out": 44.7, "volume": -18, "fadeIn": 1.0, "fadeOut": 2.0 } ] }
  ],
  "captions": {
    "style": { "font": "Inter", "fontSize": 72, "color": "#ffffff", "bold": true, "y": 0.78,
               "stroke": { "color": "#000000", "opacity": 1, "width": 6 },
               "background": { "color": "#000000", "opacity": 0.6 } },
    "items": [ { "start": 0.5, "end": 1.8, "text": "nobody tells you this part" } ]
  },
  "titles": [
    { "start": 0, "end": 3, "text": "Part 3", "font": "Inter", "fontSize": 120, "color": "#ffdd00", "x": 0.5, "y": 0.2 }
  ],
  "transitions": [ { "track": "V1", "at": 34.7, "kind": "crossDissolve", "duration": 0.5 } ],
  "markers": [ { "t": 12.0, "name": "hook" } ]
}

Fields

The table lists every field. A path ending in [] is an array, and the rows under it describe each item. Rules are what schema.json checks on the field alone: a range of numbers ("16 to 8,192", "above 0", "at most 24"), a length ("1 to 200 characters", "at most 10,000 items"), the values allowed ("one of: …") and a pattern in italics, listed after the tables. Rules the schema can't state are in Meaning, and CutConvert checks them too: those that need other fields or the timeline's frames, and a few on one field, such as the eight timeline rates and no more than 64 channels in all.

FieldTypeRequiredRulesMeaning
cutconvertstringyesexactly "edit/1"The format and version.
namestringyes1 to 200 characters; one lineThe project and timeline name.
timelineobjectyesThe timeline's frame rate, size and start.
timeline.fpsnumberyesabove 0One of 23.976, 24, 25, 29.97, 30, 50, 59.94 or 60. 23.976, 29.97 and 59.94 are the exact NTSC rates (24000/1001 and so on).
timeline.widthintegeryes16 to 8,192Canvas width in pixels.
timeline.heightintegeryes16 to 8,192Canvas height in pixels.
timeline.startTimecodestringnotimecodeDrop frame (;) only at 29.97 or 59.94, and a frame the rate has. Defaults to 00:00:00:00.
media[]arrayyes1 to 1,000 itemsThe files the edit uses.
media[].idstringyesidYour id for the file, unique in the document.
media[].namestringyes1 to 200 characters; one lineThe file name, such as episode-41.mp4. The editors look for this name when they relink.
media[].pathstringnoat most 4,096 characters; absolute pathThe file's path on the editing computer, such as /Users/sam/Movies/episode-41.mp4, D:\Footage\episode-41.mp4 or \\server\share\episode-41.mp4. Leave it out and each editor asks for the file by name.
media[].durationnumberyesabove 0, up to 1,000,000The file's length in seconds.
media[].fpsnumberfor video1 to 1,000The file's frame rate. 23.976, 23.98, 29.97 and 59.94 are the exact NTSC rates. Give it, with width and height, for any file with a picture.
media[].widthintegerfor video1 to 16,384The picture's width in pixels.
media[].heightintegerfor video1 to 16,384The picture's height in pixels.
media[].audioobjectfor soundThe file's sound. Leave it out only when the file has no sound. A file has a picture, sound or both.
media[].audio.streamsinteger[]yes1 to 16 items; each 1 to 64Channels per sound stream, and no more than 64 channels in all. [2] is one stereo stream.
media[].audio.sampleRateintegeryes8,000 to 192,000Samples per second.
video[]arraynoat most 100 itemsVideo tracks, bottom first.
video[].namestringno1 to 200 characters; one lineThe track's name, which transitions[].track uses; of the four editors only DaVinci Resolve shows it. Defaults to V1, V2 and so on. Unique among video tracks.
video[].clips[]arrayyesat most 10,000 itemsThe track's clips. They may leave gaps but must not overlap.
video[].clips[].mediastringyesThe id of a media file with a picture. If the file has sound, the sound comes too, on an audio track of its own.
video[].clips[].startnumberyes0 to 1,000,000Where the clip starts on the timeline, in seconds.
video[].clips[].innumberyes0 to 1,000,000Where the clip starts in its file, in seconds.
video[].clips[].outnumberyes0 to 1,000,000Where the clip ends in its file, in seconds. After in, and no later than the file's duration.
video[].clips[].positionobjectnoWhere the picture's centre sits. Leave it out to centre the picture.
video[].clips[].position.xnumberyes−10 to 10Fraction of the frame width. When there are keyframes, they set the position instead.
video[].clips[].position.ynumberyes−10 to 10Fraction of the frame height.
video[].clips[].position.keyframes[]arraynoat most 1,000 itemsMovement over the clip, in time order. Between keyframes the position moves in a straight line.
video[].clips[].position.keyframes[].tnumberyes0 to 1,000,000Seconds from the clip's start on the timeline, no later than the clip's length.
video[].clips[].position.keyframes[].xnumberyes−10 to 10Fraction of the frame width.
video[].clips[].position.keyframes[].ynumberyes−10 to 10Fraction of the frame height.
video[].clips[].scalenumbernoabove 0, up to 10,000Size as a percentage of the file's own pixels: 100 shows a 1920×1080 picture at 1920×1080. Leave it out to fit the picture inside the frame.
video[].clips[].volumenumbernoat most 24The clip's sound level in dB. Defaults to 0.
video[].clips[].speednumberno10 to 10,000Constant speed as a percentage: 200 plays twice as fast and 50 at half speed. Defaults to 100.
audio[]arraynoat most 100 itemsAudio tracks, after the tracks that carry the video clips' sound.
audio[].namestringno1 to 200 characters; one lineThe track's name, which transitions[].track uses; of the four editors only DaVinci Resolve shows it. Defaults to its place among all the audio tracks, counting the video clips' sound first: after one track of it, audio[0] is A2. Unique among audio tracks, the tracks of the video clips' sound (A1…) included.
audio[].clips[]arrayyesat most 10,000 itemsThe track's clips. They may leave gaps but must not overlap.
audio[].clips[].mediastringyesThe id of a media file with sound.
audio[].clips[].startnumberyes0 to 1,000,000Where the clip starts on the timeline, in seconds.
audio[].clips[].innumberyes0 to 1,000,000Where the clip starts in its file, in seconds.
audio[].clips[].outnumberyes0 to 1,000,000Where the clip ends in its file, in seconds. After in, and no later than the file's duration.
audio[].clips[].volumenumbernoat most 24The clip's level in dB. Defaults to 0.
audio[].clips[].fadeInnumberno0 to 1,000,000A fade up from silence at the clip's start, in seconds. Not where a cross dissolve starts the clip.
audio[].clips[].fadeOutnumberno0 to 1,000,000A fade down to silence at the clip's end, in seconds. fadeIn and fadeOut together are no longer than the clip. Not where a cross dissolve ends the clip.
audio[].clips[].speednumberno10 to 10,000Constant speed as a percentage. Defaults to 100.
captionsobjectnoCaptions, written as editable text.
captions.stylestylenoThe look every caption shares.
captions.items[]arrayyesat most 20,000 itemsThe captions, in time order, not overlapping.
captions.items[].startnumberyes0 to 1,000,000When the caption appears, in seconds.
captions.items[].endnumberyes0 to 1,000,000When it goes, in seconds.
captions.items[].textstringyes1 to 2,000 characters; textThe words. \n starts a new line.
captions.items[].stylestylenoChanges to the shared style for this caption only. Each field given replaces the shared one; stroke and background change field by field.
titles[]arraynoat most 1,000 itemsText on screen, such as a title card. Titles may overlap.
titles[].startnumberyes0 to 1,000,000When the title appears, in seconds.
titles[].endnumberyes0 to 1,000,000When it goes, in seconds.
titles[].textstringyes1 to 2,000 characters; textThe words. \n starts a new line.
titles[].font … titles[].backgroundstyle fieldsnoThe title's look, using the style fields below.
transitions[]arraynoat most 10,000 itemsCross dissolves between clips that meet.
transitions[].trackstringyes1 to 200 characters; one lineThe name of the video or audio track. A name that a video track and an audio track share is an error here: rename one. A track of the video clips' sound (A1…) can't be named: a dissolve on its video track crossfades that sound.
transitions[].atnumberyes0 to 1,000,000The time where one clip ends and the next starts, in seconds. One transition per cut.
transitions[].kindstringyesone of: "crossDissolve"The kind of transition.
transitions[].durationnumberyesabove 0, up to 1,000,000The dissolve's length in seconds.
markers[]arraynoat most 10,000 itemsTimeline markers.
markers[].tnumberyes0 to 1,000,000The marker's time in seconds.
markers[].namestringyesat most 200 characters; one lineThe marker's name.

Style fields

captions.style, captions.items[].style and each title use these fields. All are optional.

FieldTypeRulesMeaning
fontstring1 to 200 characters; one lineThe font family, such as Inter. The editing computer needs the font installed. Left out, each editor uses its own: Helvetica in Premiere Pro and Final Cut Pro, Arial in DaVinci Resolve, CapCut's default in CapCut.
fontSizenumberabove 0, up to 1,000Pixels on the timeline's canvas, and no more than 4 × the canvas width or about 9.26 × its height (10,000 on Final Cut's 1080-line title canvas). Defaults to 1/20 of the canvas's shorter side: 54 on 1920×1080 or 1080×1920.
colorstring#rrggbbDefaults to white.
boldbooleanBold text.
xnumber−10 to 10Where the text's centre sits, as a fraction of the frame width. Defaults to 0.5.
ynumber−10 to 10Where the text's centre sits, as a fraction of the frame height. Captions default to 0.85, near the bottom, and titles to 0.5.
strokeobjectAn outline round the letters.
stroke.colorstring#rrggbbDefaults to black.
stroke.opacitynumber0 to 1Defaults to 1.
stroke.widthnumber0 to 1,000Pixels on the timeline's canvas. Defaults to 4.
backgroundobjectA box behind the text.
background.colorstring#rrggbbDefaults to black.
background.opacitynumber0 to 1Defaults to 1.

Patterns

Each pattern in the Rules column, with the regular expression edit-schema.json gives it. A string that also holds half of a surrogate pair on its own is refused, which no pattern can say.

  • one line: no line break or other control character. ^[^\u0000-\u001f\u007f-\u009f]*$
  • text: line breaks and tabs, but no other control character. ^[^\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]*$
  • id: 1 to 64 letters, digits, _, . or -. ^[A-Za-z0-9_.-]{1,64}$
  • timecode: HH:MM:SS:FF, or HH:MM:SS;FF for drop frame, at a time of day: hours up to 23, minutes and seconds up to 59. ^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d[:;]\d\d$
  • absolute path: one line that starts with /, a drive such as D:\ or D:/, or \\server\. ^(?:\/|[A-Za-z]:[\\/]|\\\\[^\\/\u0000-\u001f\u007f-\u009f]+[\\/])[^\u0000-\u001f\u007f-\u009f]*$
  • #rrggbb: a colour as six hex digits, such as #ffdd00. ^#[0-9a-fA-F]{6}$

How the document becomes a project

  • Tracks. Video tracks stack in order, video[0] at the bottom. Titles go on tracks above them and captions on one track at the top. The sound of the video clips comes first among the audio tracks, then audio[] in order.
  • A video clip brings its sound. When its media has audio, the clip's sound is placed under it at the same times, from the same file, at the clip's volume. Whether the two come in linked depends on the editor (see the table below). To keep the picture without the sound, set volume to −96: the sound stays in the project, silent. Premiere Pro and CapCut bring it in at their lowest level, ready to raise; Final Cut Pro and DaVinci Resolve bring it in as a disabled clip, to enable and then raise.
  • Cross dissolves. A dissolve sits across the cut at at, half before and half after (an odd frame goes to the side with room). It needs spare footage on both sides: the outgoing clip's file must run on past its out, and the incoming clip's file must start before its in. When one side has too little for its half and the other has room for the whole dissolve, it moves wholly to that side of the cut (edit-transition-moved). Otherwise it is shortened to the longest that fits, centred or to one side (edit-transition-shortened), or left out when there is no spare footage at all (edit-transition-dropped). A dissolve also stays inside its two clips, clear of a fade or dissolve at their other ends. A dissolve on a video track also crossfades the clips' sound, when both have sound.
  • Fades on audio clips become each editor's own fade, not keyframes.
  • Speed changes the clip's length on the timeline: a clip from 10 s to 20 s in its file at 200% lasts 5 s.
  • Position keyframes count from the clip's first frame on the timeline, whatever its speed.

What each editor gets

Version 1 asks for nothing the four editors can't open, but a few things change on the way. This table lists what each editor does; where what is lost depends on the document, such as a start timecode CapCut can't hold or a dissolve without spare footage, it also comes back as a warning, with a code and a sentence.

CapCutPremiere ProDaVinci ResolveFinal Cut Pro
CaptionsCapCut captions on a caption track, each in its own lookText generator clips on the top trackText+ clips on the top trackBasic Titles on the top lane
TitlesTextText generator clipsText+Basic Titles
Stroke and boxBothNeitherBothStroke, not the box
BoldCarriedNot carriedCarriedCarried
Audio fadesThe clip's fade in and fade outCross Fade (+3dB) at the clip's edgeAn edge fade; where another clip meets the faded edge, the clip's volumeThe clip's own fade handles
Sound under a cross dissolveThe two sounds overlap, each fading: CapCut has no crossfadeCross Fade (+3dB)Cross Fade +3 dBAudio Crossfade when centred with footage on both sides; otherwise each clip fades on its own side
Media with no pathThe file by name: CapCut's Link media window lists it on openingOffline, by nameOffline, by nameOffline, in /CutConvert Offline Media; File > Relink Files finds it
Picture and soundOne clip that plays its own sound, except at a cross dissolve or for media with no path, where the sound is a separate clip on an audio trackLinked clips; stereo sound is two mono clipsSeparate clips at the same timesSeparate connected clips, the picture above the storyline and the sound below it, not linked
Sound at −96 dB or lowerVolume 0Level 0 (−∞ dB)A disabled clipA disabled clip at −96 dB
Track namesNot shown: CapCut's tracks have no namesNot carried: tracks are numbered V1… and A1…KeptNot carried: Final Cut has lanes, not tracks
Start timecodeNot carried: CapCut timelines start at 00:00:00:00 (edit-capcut-start-timecode); drop-frame display is keptCarriedCarriedCarried

Each editor has a page with what it showed when the test documents were opened in it: CapCut, Premiere Pro, DaVinci Resolve and Final Cut Pro.

Not in version 1

Variable speed, nested timelines, transitions other than cross dissolve, effects, colour, multicam, still images, scale or opacity keyframes, marker colours, and trimming media on the server.

Back to top

Questions about the Edit API: [email protected]