Apexify Docs Engines Node Advanced renderSceneToGIF Advanced / Scene · guide
renderSceneToGIF Current Apexify.js 6.0.0 documentation for renderSceneToGIF.
apexify.js Runtime: node CURRENT Since 6.0.0
Signature (conceptual):
1 renderSceneToGIF ( 2 scene : SceneRenderInput , 3 gif : { 4 options : GIFOptions ; 5 gifFrames ? : SceneGifInputFrame []; 6 prependComposedRaster ? : boolean ; 7 composedFrameDuration ? : number ; 8 composedFrameRepeat ? : number ; 9 10 sceneRender ? : SceneRenderOptions ; 11 } 12 ): Promise < GIFResults | Buffer | string | undefined >
Pipeline: scene → SceneCreator.render(scene, gif.sceneRender) → composed PNG → build GIFInputFrame[] → GIFCreator.createGIF(frames, options) .
# Rules that differ from plain createGIF
gif.options.onStart must be absentSceneCreate.renderSceneToGIF throws: use createGIF alone if you need onStart .At least one frame after expansionEither prepended composed raster and/or gifFrames (after repeat expansion). gif.sceneRenderOptional SceneRenderOptions passed to SceneCreator.render when rasterizing scene — validate , maxSurfaceDepth , resolveAssetRefs , … (same knobs as renderScene ; $ resolution defaults on here).
SceneGifInputFrame = GIFInputFrame & { repeat?: number } — each logical frame can be duplicated repeat times in the final list.
# Variant: sceneRender on the composed frame
1 await painter . renderSceneToGIF ( scene , { 2 gifFrames : [], 3 options : { width : scene . width , height : scene . height , delay : 400 }, 4 prependComposedRaster : true , 5 sceneRender : { maxSurfaceDepth : 12 }, 6 });
Same shape for renderSceneToVideoFrames — video.sceneRender is passed into SceneCreator.render before FFmpeg.
# Variant: composed only (hold on first frame)
1 import { ApexPainter } from "apexify.js" ; 2 import fs from "fs" ; 3 4 const painter = new ApexPainter (); 5 6 const scene = { 7 width : 320 , 8 height : 200 , 9 background : { colorBg : "#312e81" }, 10 layers : [{ type : "text" , texts : [{ text : "Hold" , x : 24 , y : 80 , fontSize : 36 , color : "#fff" }] }], 11 }; 12 13 const out = await painter . renderSceneToGIF ( scene , { 14 gifFrames : [], 15 options : { width : 320 , height : 200 , delay : 500 }, 16 prependComposedRaster : true , 17 composedFrameDuration : 800 , 18 composedFrameRepeat : 3 , 19 }); 20 21 if ( Buffer . isBuffer ( out )) await fs . promises . writeFile ( "hold.gif" , out );
1 const out = await painter . renderSceneToGIF ( scene , { 2 gifFrames : [ 3 { buffer : await fs . promises . readFile ( "./f1.png" ), duration : 120 , repeat : 2 }, 4 { buffer : await fs . promises . readFile ( "./f2.png" ), duration : 120 }, 5 ], 6 options : { width : 320 , height : 200 , delay : 120 }, 7 prependComposedRaster : true , 8 composedFrameDuration : 200 , 9 composedFrameRepeat : 1 , 10 });
Frame order: [composed × repeat?, …expanded gifFrames] when prepend is true.
# Variant: no composed — only gifFrames
1 const out = await painter . renderSceneToGIF ( scene , { 2 gifFrames : [ 3 { buffer : frameA , duration : 100 }, 4 { buffer : frameB , duration : 100 }, 5 ], 6 options : { width : 400 , height : 300 , delay : 100 }, 7 prependComposedRaster : false , 8 });
Still renders scene internally (for consistency / future use), but only expanded gifFrames go to the encoder — you must supply non-empty gifFrames .
# Variant: composedFrameDuration vs options.delay
composedFrameDuration : ms for the prepended composed PNG frame(s).
options.delay : used as default for composedFrameDuration when composedFrameDuration is omitted and options.delay is a number ; else default 100 ms.
1 await painter . renderSceneToGIF ( scene , { 2 gifFrames : [{ buffer : extra , duration : 50 }], 3 options : { width : 200 , height : 200 , delay : 33 }, 4 composedFrameDuration : 1000 , 5 });
# Variant: handle non-Buffer return
createGIF may return GIFResults , Buffer , string , etc.
1 const out = await painter . renderSceneToGIF ( scene , { gifFrames : [], options : { width : 100 , height : 100 } }); 2 3 if ( Buffer . isBuffer ( out )) { 4 await fs . promises . writeFile ( "a.gif" , out ); 5 } else if ( out && typeof out === "object" && "gif" in out && Buffer . isBuffer (( out as { gif : Buffer }). gif )) { 6 await fs . promises . writeFile ( "a.gif" , ( out as { gif : Buffer }). gif ); 7 }
# Variant: onEnd still allowed
1 await painter . renderSceneToGIF ( scene , { 2 gifFrames : [{ buffer : b , duration : 100 }], 3 options : { 4 width : 200 , 5 height : 200 , 6 delay : 100 , 7 onEnd : ( results ) => { 8 console . log ( "done" , results ); 9 }, 10 }, 11 });