{"schemaVersion":1,"id":"recommended.sm-motion-graphics","version":"1.0.0","name":"Motion graphics workflow","description":"An editable production workflow using Motion graphics v2.0.0.","stages":[{"id":"main","blockId":"sm.motion-graphics","version":"2.0.0","label":"Motion graphics"}],"connections":[],"packages":[{"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"sm.motion-graphics","version":"2.0.0","name":"Motion graphics","description":"Add timed titles, kinetic text, figures, graphs, and transitions to a connected timeline. Review the exact Editor change before applying it.","kind":"editor-extension","runtime":"javascript","entry":"src/run.js","license":"MIT","provenance":{"notice":"Original source (authorship declared by the packager)\nLicense: MIT\nChanges: Original implementation declared by the packager; no reused repository or dependency code.\nFiles: LICENSE, src/run.js\n\nMIT License\n\nCopyright (c) 2026 StillMade contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","portableSources":[{"kind":"original","license":"MIT","paths":["LICENSE","src/run.js"],"evidence":["upstream/0/LICENSE","upstream/0/src/run.js"],"changes":"Original implementation declared by the packager; no reused repository or dependency code."}]},"inputs":{"timeline":{"type":"timeline","primary":true,"semantic":"timeline","required":false,"description":"An explicitly connected Editor timeline.","sources":["user","upstream"]},"projectTimeline":{"type":"timeline","context":"timeline","semantic":"timeline","required":false,"description":"Current project timeline when no Block is connected.","sources":["project"]},"plan":{"type":"json","semantic":"motion_graphics_plan","required":false,"description":"Timed motion graphic elements to layer on the timeline.","sources":["user","upstream"]}},"outputs":{"timeline":{"type":"timeline","primary":true,"semantic":"timeline","description":"Timeline with the motion graphic layers."},"edit":{"type":"workspace-edit","semantic":"editor_workspace_edit","description":"The exact Editor change for review."}},"permissions":{"project":["context.timeline.read","context.editor.read","workspace.editor.propose"],"network":[],"filesystem":[],"secrets":[]},"ui":[],"platforms":{"phone":{"supported":true},"browser":{"supported":true},"desktop":{"supported":true}}},"code":"const before=JSON.parse(JSON.stringify(input.timeline||input.projectTimeline||{}));\nif(before.schemaVersion!==1||typeof before.activeTimelineId!=='string'||!before.activeTimelineId)throw new Error('Connect or open a version 1 Editor timeline.');\nconst elements=input.plan?.elements;\nif(!Array.isArray(elements)||elements.length<1||elements.length>100)throw new Error('Provide 1–100 motion graphic elements.');\nconst after=JSON.parse(JSON.stringify(before));\nconst kinds=new Set(['animated_title','kinetic_emphasis','lower_third','figure_sweep','animated_graph','graphic_transition']);\nconst ids=new Set(['clips','captions','textOverlays','graphs','figureSweeps'].flatMap(key=>(after[key]||[]).map(item=>item.id)));\nconst fresh=stem=>{let id=stem,n=2;while(ids.has(id))id=stem+'-'+n++;ids.add(id);return id;};\nconst text=(value,max=5000)=>typeof value==='string'&&value.trim()&&value.length<=max?value.trim():null;\nconst finite=(value,min,max)=>Number.isFinite(value)&&value>=min&&value<=max;\nconst add=(key,item)=>{if(!Array.isArray(after[key]))after[key]=[];after[key].push(item);};\nconst track=(id,type)=>{if(!Array.isArray(after.tracks))after.tracks=[];if(!after.tracks.some(item=>item.id===id))after.tracks.push({id,type,label:type==='caption'?'Captions':type==='text'?'Text':'Overlays'});};\nfor(let index=0;index<elements.length;index++){\n const el=elements[index];\n if(!el||typeof el!=='object'||Array.isArray(el)||!kinds.has(el.type))throw new Error('Choose a supported motion graphic type.');\n const start=Number(el.start),end=Number(el.end);\n if(!finite(start,0,86400)||!finite(end,start+.001,86400))throw new Error('Motion graphics need bounded start and end times.');\n const mode=el.mode==='fullscreen'?'fullscreen':'overlay';\n if(el.type==='animated_title'||el.type==='lower_third'){\n  const title=text(el.text);if(!title)throw new Error('A motion title needs text.');\n  track('captions','caption');const lower=el.type==='lower_third';\n  const caption={id:fresh(`mg-${lower?'lower':'title'}-${index}`),trackId:'captions',start,end,text:title,position:lower?'lower_third':el.style?.position==='top'?'top':el.style?.position==='bottom'?'bottom':'center',size:lower?'m':el.style?.size||'lg',animation:lower?'rise':el.animation||'reveal',mgTitle:!lower,polish:true};\n  if(lower){caption.background=/^#[0-9a-f]{6}$/i.test(el.accent||'')?el.accent:'#111418';caption.backgroundOpacity=85;}\n  else if(mode==='fullscreen'){caption.background='#000000';caption.backgroundOpacity=34;}\n  if(text(el.subtitle,1000))caption.subtitle=el.subtitle.trim();\n  add('captions',caption);\n }else if(el.type==='kinetic_emphasis'){\n  const title=text(el.text);if(!title)throw new Error('Kinetic emphasis needs text.');\n  track('text','text');add('textOverlays',{id:fresh(`mg-kinetic-${index}`),trackId:'text',start,end,text:title,position:el.style?.position||'center',size:el.style?.size||'xl',animation:el.animation||'word_sequence',words:Array.isArray(el.words)?el.words:null,emphasis:true,polish:true});\n }else if(el.type==='figure_sweep'){\n  if(!finite(el.value,-1e9,1e9))throw new Error('A figure needs a finite value.');\n  track('overlay','overlay');add('figureSweeps',{id:fresh(`mg-figure-${index}`),trackId:'overlay',start,end,value:el.value,prefix:text(el.prefix,40)||'',suffix:text(el.suffix,40)||'',label:text(el.label,200)||'',decimals:Math.min(2,Math.max(0,Number.isInteger(el.decimals)?el.decimals:0)),easing:'ease-out',x:50,y:50,size:mode==='fullscreen'?'xl':'lg',color:'#ffffff',polish:true});\n }else if(el.type==='animated_graph'){\n  if(!Array.isArray(el.series)||el.series.length<1||el.series.length>24||!el.series.every(item=>text(item?.label,100)&&finite(item?.value,-1e9,1e9)))throw new Error('A graph needs 1–24 labeled finite values.');\n  track('overlay','overlay');add('graphs',{id:fresh(`mg-graph-${index}`),trackId:'overlay',start,end,chart:['bar','line','pie'].includes(el.chart)?el.chart:'bar',series:el.series.map(item=>({label:item.label.trim(),value:item.value})),unit:text(el.unit,40)||'',title:text(el.title,200)||'',box:mode==='fullscreen'?{x:12,y:16,w:76,h:66}:{x:54,y:10,w:42,h:42},palette:['#6ea8ff','#9b8cff','#5fd0c0','#ffd166','#ff7b9c','#7ee787'],easing:'ease-out',polish:true});\n }else{\n  const outgoing=el.on_cut_between?.[0],clip=after.clips?.find(item=>item.id===outgoing);\n  if(!clip)throw new Error('A transition needs an exact outgoing clip.');\n  const duration=Number(el.duration);\n  if(!finite(duration,.05,5))throw new Error('A transition duration must be 0.05–5 seconds.');\n  clip.transition={type:typeof el.style==='string'&&el.style?el.style:'wipe',duration};\n }\n}\nreturn {timeline:after,edit:{schemaVersion:1,title:'Apply motion graphics',field:'editor',before,after}};\n","tests":[{"name":"Layers a title and graph on the source timeline","input":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[],"textOverlays":[]},"plan":{"elements":[{"type":"animated_title","start":0,"end":2,"text":"A new chapter","mode":"fullscreen"},{"type":"animated_graph","start":2,"end":4,"title":"Growth","series":[{"label":"Jan","value":10},{"label":"Feb","value":20}]}]}},"expected":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"},{"id":"captions","type":"caption","label":"Captions"},{"id":"overlay","type":"overlay","label":"Overlays"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[{"id":"mg-title-0","trackId":"captions","start":0,"end":2,"text":"A new chapter","position":"center","size":"lg","animation":"reveal","mgTitle":true,"polish":true,"background":"#000000","backgroundOpacity":34}],"textOverlays":[],"graphs":[{"id":"mg-graph-1","trackId":"overlay","start":2,"end":4,"chart":"bar","series":[{"label":"Jan","value":10},{"label":"Feb","value":20}],"unit":"","title":"Growth","box":{"x":54,"y":10,"w":42,"h":42},"palette":["#6ea8ff","#9b8cff","#5fd0c0","#ffd166","#ff7b9c","#7ee787"],"easing":"ease-out","polish":true}]},"edit":{"schemaVersion":1,"title":"Apply motion graphics","field":"editor","before":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[],"textOverlays":[]},"after":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"},{"id":"captions","type":"caption","label":"Captions"},{"id":"overlay","type":"overlay","label":"Overlays"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[{"id":"mg-title-0","trackId":"captions","start":0,"end":2,"text":"A new chapter","position":"center","size":"lg","animation":"reveal","mgTitle":true,"polish":true,"background":"#000000","backgroundOpacity":34}],"textOverlays":[],"graphs":[{"id":"mg-graph-1","trackId":"overlay","start":2,"end":4,"chart":"bar","series":[{"label":"Jan","value":10},{"label":"Feb","value":20}],"unit":"","title":"Growth","box":{"x":54,"y":10,"w":42,"h":42},"palette":["#6ea8ff","#9b8cff","#5fd0c0","#ffd166","#ff7b9c","#7ee787"],"easing":"ease-out","polish":true}]}}}},{"name":"Keeps existing IDs while placing emphasis, figure, and transition","input":{"projectTimeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[{"id":"mg-kinetic-0","trackId":"captions","start":0,"end":1,"text":"Existing"}],"textOverlays":[]},"plan":{"elements":[{"type":"kinetic_emphasis","start":0,"end":2,"text":"Keep going"},{"type":"figure_sweep","start":2,"end":4,"value":25,"suffix":"%"},{"type":"graphic_transition","start":4,"end":5,"on_cut_between":["clip-1","clip-2"],"duration":0.5}]}},"expected":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"},{"id":"text","type":"text","label":"Text"},{"id":"overlay","type":"overlay","label":"Overlays"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4","transition":{"type":"wipe","duration":0.5}}],"audioItems":[],"captions":[{"id":"mg-kinetic-0","trackId":"captions","start":0,"end":1,"text":"Existing"}],"textOverlays":[{"id":"mg-kinetic-0-2","trackId":"text","start":0,"end":2,"text":"Keep going","position":"center","size":"xl","animation":"word_sequence","words":null,"emphasis":true,"polish":true}],"figureSweeps":[{"id":"mg-figure-1","trackId":"overlay","start":2,"end":4,"value":25,"prefix":"","suffix":"%","label":"","decimals":0,"easing":"ease-out","x":50,"y":50,"size":"lg","color":"#ffffff","polish":true}]},"edit":{"schemaVersion":1,"title":"Apply motion graphics","field":"editor","before":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4"}],"audioItems":[],"captions":[{"id":"mg-kinetic-0","trackId":"captions","start":0,"end":1,"text":"Existing"}],"textOverlays":[]},"after":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video","type":"video","label":"Video"},{"id":"text","type":"text","label":"Text"},{"id":"overlay","type":"overlay","label":"Overlays"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":5,"url":"/api/media/owner/clip.mp4","transition":{"type":"wipe","duration":0.5}}],"audioItems":[],"captions":[{"id":"mg-kinetic-0","trackId":"captions","start":0,"end":1,"text":"Existing"}],"textOverlays":[{"id":"mg-kinetic-0-2","trackId":"text","start":0,"end":2,"text":"Keep going","position":"center","size":"xl","animation":"word_sequence","words":null,"emphasis":true,"polish":true}],"figureSweeps":[{"id":"mg-figure-1","trackId":"overlay","start":2,"end":4,"value":25,"prefix":"","suffix":"%","label":"","decimals":0,"easing":"ease-out","x":50,"y":50,"size":"lg","color":"#ffffff","polish":true}]}}}}],"portable":{"format":"stillmade-block/1","dependencies":[],"sources":[{"kind":"original","license":"MIT","paths":["LICENSE","src/run.js"],"evidence":["upstream/0/LICENSE","upstream/0/src/run.js"],"changes":"Original implementation declared by the packager; no reused repository or dependency code."}],"files":{"upstream/0/LICENSE":"MIT License\n\nCopyright (c) 2026 StillMade contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","upstream/0/src/run.js":"const before=JSON.parse(JSON.stringify(input.timeline||input.projectTimeline||{}));\nif(before.schemaVersion!==1||typeof before.activeTimelineId!=='string'||!before.activeTimelineId)throw new Error('Connect or open a version 1 Editor timeline.');\nconst elements=input.plan?.elements;\nif(!Array.isArray(elements)||elements.length<1||elements.length>100)throw new Error('Provide 1–100 motion graphic elements.');\nconst after=JSON.parse(JSON.stringify(before));\nconst kinds=new Set(['animated_title','kinetic_emphasis','lower_third','figure_sweep','animated_graph','graphic_transition']);\nconst ids=new Set(['clips','captions','textOverlays','graphs','figureSweeps'].flatMap(key=>(after[key]||[]).map(item=>item.id)));\nconst fresh=stem=>{let id=stem,n=2;while(ids.has(id))id=stem+'-'+n++;ids.add(id);return id;};\nconst text=(value,max=5000)=>typeof value==='string'&&value.trim()&&value.length<=max?value.trim():null;\nconst finite=(value,min,max)=>Number.isFinite(value)&&value>=min&&value<=max;\nconst add=(key,item)=>{if(!Array.isArray(after[key]))after[key]=[];after[key].push(item);};\nconst track=(id,type)=>{if(!Array.isArray(after.tracks))after.tracks=[];if(!after.tracks.some(item=>item.id===id))after.tracks.push({id,type,label:type==='caption'?'Captions':type==='text'?'Text':'Overlays'});};\nfor(let index=0;index<elements.length;index++){\n const el=elements[index];\n if(!el||typeof el!=='object'||Array.isArray(el)||!kinds.has(el.type))throw new Error('Choose a supported motion graphic type.');\n const start=Number(el.start),end=Number(el.end);\n if(!finite(start,0,86400)||!finite(end,start+.001,86400))throw new Error('Motion graphics need bounded start and end times.');\n const mode=el.mode==='fullscreen'?'fullscreen':'overlay';\n if(el.type==='animated_title'||el.type==='lower_third'){\n  const title=text(el.text);if(!title)throw new Error('A motion title needs text.');\n  track('captions','caption');const lower=el.type==='lower_third';\n  const caption={id:fresh(`mg-${lower?'lower':'title'}-${index}`),trackId:'captions',start,end,text:title,position:lower?'lower_third':el.style?.position==='top'?'top':el.style?.position==='bottom'?'bottom':'center',size:lower?'m':el.style?.size||'lg',animation:lower?'rise':el.animation||'reveal',mgTitle:!lower,polish:true};\n  if(lower){caption.background=/^#[0-9a-f]{6}$/i.test(el.accent||'')?el.accent:'#111418';caption.backgroundOpacity=85;}\n  else if(mode==='fullscreen'){caption.background='#000000';caption.backgroundOpacity=34;}\n  if(text(el.subtitle,1000))caption.subtitle=el.subtitle.trim();\n  add('captions',caption);\n }else if(el.type==='kinetic_emphasis'){\n  const title=text(el.text);if(!title)throw new Error('Kinetic emphasis needs text.');\n  track('text','text');add('textOverlays',{id:fresh(`mg-kinetic-${index}`),trackId:'text',start,end,text:title,position:el.style?.position||'center',size:el.style?.size||'xl',animation:el.animation||'word_sequence',words:Array.isArray(el.words)?el.words:null,emphasis:true,polish:true});\n }else if(el.type==='figure_sweep'){\n  if(!finite(el.value,-1e9,1e9))throw new Error('A figure needs a finite value.');\n  track('overlay','overlay');add('figureSweeps',{id:fresh(`mg-figure-${index}`),trackId:'overlay',start,end,value:el.value,prefix:text(el.prefix,40)||'',suffix:text(el.suffix,40)||'',label:text(el.label,200)||'',decimals:Math.min(2,Math.max(0,Number.isInteger(el.decimals)?el.decimals:0)),easing:'ease-out',x:50,y:50,size:mode==='fullscreen'?'xl':'lg',color:'#ffffff',polish:true});\n }else if(el.type==='animated_graph'){\n  if(!Array.isArray(el.series)||el.series.length<1||el.series.length>24||!el.series.every(item=>text(item?.label,100)&&finite(item?.value,-1e9,1e9)))throw new Error('A graph needs 1–24 labeled finite values.');\n  track('overlay','overlay');add('graphs',{id:fresh(`mg-graph-${index}`),trackId:'overlay',start,end,chart:['bar','line','pie'].includes(el.chart)?el.chart:'bar',series:el.series.map(item=>({label:item.label.trim(),value:item.value})),unit:text(el.unit,40)||'',title:text(el.title,200)||'',box:mode==='fullscreen'?{x:12,y:16,w:76,h:66}:{x:54,y:10,w:42,h:42},palette:['#6ea8ff','#9b8cff','#5fd0c0','#ffd166','#ff7b9c','#7ee787'],easing:'ease-out',polish:true});\n }else{\n  const outgoing=el.on_cut_between?.[0],clip=after.clips?.find(item=>item.id===outgoing);\n  if(!clip)throw new Error('A transition needs an exact outgoing clip.');\n  const duration=Number(el.duration);\n  if(!finite(duration,.05,5))throw new Error('A transition duration must be 0.05–5 seconds.');\n  clip.transition={type:typeof el.style==='string'&&el.style?el.style:'wipe',duration};\n }\n}\nreturn {timeline:after,edit:{schemaVersion:1,title:'Apply motion graphics',field:'editor',before,after}};\n"},"lineage":{"parents":[],"changes":"Packaged original Block source for StillMade."}}}],"license":"MIT"}